package com.yanmaohu.yulia;

import com.yanmaohu.yulia.bean.*;
import com.yanmaohu.yulia.statement.*;
import com.yanmaohu.yulia.token.TokenType;

import java.io.InputStream;
import java.io.Reader;

/**
 * @author Bright Lee
 */
public abstract class Generator {

    private final StringBuilder BUFFER = new StringBuilder(4096);
    private final Parser PARSER;

    protected Generator(Reader reader) {
        PARSER = new Parser(reader);
    }

    protected Generator(InputStream in, String charseName) {
        PARSER = new Parser(in, charseName);
    }

    protected Generator(InputStream in) {
        PARSER = new Parser(in, "UTF-8");
    }

    protected Generator(String sql) {
        PARSER = new Parser(sql);
    }

    public final String generate() {
        Statement statement = PARSER.parse();
        if (statement == null) {
            return null;
        }
        BUFFER.setLength(0);
        generate(statement);
        BUFFER.append(TokenType.SEMICOLON.getContent());
        return BUFFER.toString();
    }

    private void generate(Statement statement) {
        if (statement instanceof AllocateCursorStatement) {
            AllocateCursorStatement allocateCursorStatement = (AllocateCursorStatement) statement;
            generate(allocateCursorStatement);
            return;
        }
        if (statement instanceof AllocateDescriptorStatement) {
            AllocateDescriptorStatement allocateDescriptorStatement = (AllocateDescriptorStatement) statement;
            generate(allocateDescriptorStatement);
            return;
        }
        if (statement instanceof AlterDomainStatement) {
            AlterDomainStatement alterDomainStatement = (AlterDomainStatement) statement;
            generate(alterDomainStatement);
            return;
        }
        if (statement instanceof AlterRoutineStatement) {
            AlterRoutineStatement alterRoutineStatement = (AlterRoutineStatement) statement;
            generate(alterRoutineStatement);
            return;
        }
        if (statement instanceof AlterSequenceGeneratorStatement) {
            AlterSequenceGeneratorStatement alterSequenceGeneratorStatement = (AlterSequenceGeneratorStatement) statement;
            generate(alterSequenceGeneratorStatement);
            return;
        }
        if (statement instanceof AlterTableStatement) {
            AlterTableStatement alterTableStatement = (AlterTableStatement) statement;
            generate(alterTableStatement);
            return;
        }
        if (statement instanceof AlterTypeStatement) {
            AlterTypeStatement alterTypeStatement = (AlterTypeStatement) statement;
            generate(alterTypeStatement);
            return;
        }
        if (statement instanceof AssertionDefinition) {
            AssertionDefinition assertionDefinition = (AssertionDefinition) statement;
            generate(assertionDefinition);
            return;
        }
        if (statement instanceof CharacterSetDefinition) {
            CharacterSetDefinition characterSetDefinition = (CharacterSetDefinition) statement;
            generate(characterSetDefinition);
            return;
        }
        if (statement instanceof CloseStatement) {
            CloseStatement closeStatement = (CloseStatement) statement;
            generate(closeStatement);
            return;
        }
        if (statement instanceof CollationDefinition) {
            CollationDefinition collationDefinition = (CollationDefinition) statement;
            generate(collationDefinition);
            return;
        }
        if (statement instanceof CommitStatement) {
            CommitStatement commitStatement = (CommitStatement) statement;
            generate(commitStatement);
            return;
        }
        if (statement instanceof ConnectStatement) {
            ConnectStatement connectStatement = (ConnectStatement) statement;
            generate(connectStatement);
            return;
        }
        if (statement instanceof DeallocateDescriptorStatement) {
            DeallocateDescriptorStatement deallocateDescriptorStatement = (DeallocateDescriptorStatement) statement;
            generate(deallocateDescriptorStatement);
            return;
        }
        if (statement instanceof DeallocatePreparedStatement) {
            DeallocatePreparedStatement deallocatePreparedStatement = (DeallocatePreparedStatement) statement;
            generate(deallocatePreparedStatement);
            return;
        }
        if (statement instanceof DeclareCursorStatement) {
            DeclareCursorStatement declareCursorStatement = (DeclareCursorStatement) statement;
            generate(declareCursorStatement);
            return;
        }
        if (statement instanceof DeleteStatement) {
            DeleteStatement deleteStatement = (DeleteStatement) statement;
            generate(deleteStatement);
            return;
        }
        if (statement instanceof DescribeInputStatement) {
            DescribeInputStatement describeInputStatement = (DescribeInputStatement) statement;
            generate(describeInputStatement);
            return;
        }
        if (statement instanceof DescribeOutputStatement) {
            DescribeOutputStatement describeOutputStatement = (DescribeOutputStatement) statement;
            generate(describeOutputStatement);
            return;
        }
        if (statement instanceof DisconnectStatement) {
            DisconnectStatement disconnectStatement = (DisconnectStatement) statement;
            generate(disconnectStatement);
            return;
        }
        if (statement instanceof DomainDefinition) {
            DomainDefinition domainDefinition = (DomainDefinition) statement;
            generate(domainDefinition);
            return;
        }
        if (statement instanceof DropAssertionStatement) {
            DropAssertionStatement dropAssertionStatement = (DropAssertionStatement) statement;
            generate(dropAssertionStatement);
            return;
        }
        if (statement instanceof DropCharacterSetStatement) {
            DropCharacterSetStatement dropCharacterSetStatement = (DropCharacterSetStatement) statement;
            generate(dropCharacterSetStatement);
            return;
        }
        if (statement instanceof DropCollationStatement) {
            DropCollationStatement dropCollationStatement = (DropCollationStatement) statement;
            generate(dropCollationStatement);
            return;
        }
        if (statement instanceof DropDataTypeStatement) {
            DropDataTypeStatement dropDataTypeStatement = (DropDataTypeStatement) statement;
            generate(dropDataTypeStatement);
            return;
        }
        if (statement instanceof DropDomainStatement) {
            DropDomainStatement dropDomainStatement = (DropDomainStatement) statement;
            generate(dropDomainStatement);
            return;
        }
        if (statement instanceof DropRoleStatement) {
            DropRoleStatement dropRoleStatement = (DropRoleStatement) statement;
            generate(dropRoleStatement);
            return;
        }
        if (statement instanceof DropRoutineStatement) {
            DropRoutineStatement dropRoutineStatement = (DropRoutineStatement) statement;
            generate(dropRoutineStatement);
            return;
        }
        if (statement instanceof DropSchemaStatement) {
            DropSchemaStatement dropSchemaStatement = (DropSchemaStatement) statement;
            generate(dropSchemaStatement);
            return;
        }
        if (statement instanceof DropSequenceGeneratorStatement) {
            DropSequenceGeneratorStatement dropSequenceGeneratorStatement = (DropSequenceGeneratorStatement) statement;
            generate(dropSequenceGeneratorStatement);
            return;
        }
        if (statement instanceof DropTableStatement) {
            DropTableStatement dropTableStatement = (DropTableStatement) statement;
            generate(dropTableStatement);
            return;
        }
        if (statement instanceof DropTransformStatement) {
            DropTransformStatement dropTransformStatement = (DropTransformStatement) statement;
            generate(dropTransformStatement);
            return;
        }
        if (statement instanceof DropTransliterationStatement) {
            DropTransliterationStatement dropTransliterationStatement = (DropTransliterationStatement) statement;
            generate(dropTransliterationStatement);
            return;
        }
        if (statement instanceof DropTriggerStatement) {
            DropTriggerStatement dropTriggerStatement = (DropTriggerStatement) statement;
            generate(dropTriggerStatement);
            return;
        }
        if (statement instanceof DropUserDefinedCastStatement) {
            DropUserDefinedCastStatement dropUserDefinedCastStatement = (DropUserDefinedCastStatement) statement;
            generate(dropUserDefinedCastStatement);
            return;
        }
        if (statement instanceof DropUserDefinedOrderingStatement) {
            DropUserDefinedOrderingStatement dropUserDefinedOrderingStatement = (DropUserDefinedOrderingStatement) statement;
            generate(dropUserDefinedOrderingStatement);
            return;
        }
        if (statement instanceof DropViewStatement) {
            DropViewStatement dropViewStatement = (DropViewStatement) statement;
            generate(dropViewStatement);
            return;
        }
        if (statement instanceof DynamicCloseStatement) {
            DynamicCloseStatement dynamicCloseStatement = (DynamicCloseStatement) statement;
            generate(dynamicCloseStatement);
            return;
        }
        if (statement instanceof DynamicDeleteStatementPositioned) {
            DynamicDeleteStatementPositioned dynamicDeleteStatementPositioned = (DynamicDeleteStatementPositioned) statement;
            generate(dynamicDeleteStatementPositioned);
            return;
        }
        if (statement instanceof DynamicFetchStatement) {
            DynamicFetchStatement dynamicFetchStatement = (DynamicFetchStatement) statement;
            generate(dynamicFetchStatement);
            return;
        }
        if (statement instanceof DynamicOpenStatement) {
            DynamicOpenStatement dynamicOpenStatement = (DynamicOpenStatement) statement;
            generate(dynamicOpenStatement);
            return;
        }
        if (statement instanceof DynamicUpdateStatementPositioned) {
            DynamicUpdateStatementPositioned dynamicUpdateStatementPositioned = (DynamicUpdateStatementPositioned) statement;
            generate(dynamicUpdateStatementPositioned);
            return;
        }
        if (statement instanceof ExecuteImmediateStatement) {
            ExecuteImmediateStatement executeImmediateStatement = (ExecuteImmediateStatement) statement;
            generate(executeImmediateStatement);
            return;
        }
        if (statement instanceof ExecuteStatement) {
            ExecuteStatement executeStatement = (ExecuteStatement) statement;
            generate(executeStatement);
            return;
        }
        if (statement instanceof FetchStatement) {
            FetchStatement fetchStatement = (FetchStatement) statement;
            generate(fetchStatement);
            return;
        }
        /*if (statement instanceof FreeLocatorStatement) {
            FreeLocatorStatement freeLocatorStatement = (FreeLocatorStatement) statement;
            generate(freeLocatorStatement);
            return;
        }*/
        if (statement instanceof GetDescriptorStatement) {
            GetDescriptorStatement getDescriptorStatement = (GetDescriptorStatement) statement;
            generate(getDescriptorStatement);
            return;
        }
        if (statement instanceof GetDiagnosticsStatement) {
            GetDiagnosticsStatement getDiagnosticsStatement = (GetDiagnosticsStatement) statement;
            generate(getDiagnosticsStatement);
            return;
        }
        if (statement instanceof GrantPrivilegeStatement) {
            GrantPrivilegeStatement grantPrivilegeStatement = (GrantPrivilegeStatement) statement;
            generate(grantPrivilegeStatement);
            return;
        }
        if (statement instanceof GrantRoleStatement) {
            GrantRoleStatement grantRoleStatement = (GrantRoleStatement) statement;
            generate(grantRoleStatement);
            return;
        }
        /*if (statement instanceof HoldLocatorStatement) {
            HoldLocatorStatement holdLocatorStatement = (HoldLocatorStatement) statement;
            generate(holdLocatorStatement);
            return;
        }*/
        if (statement instanceof InsertStatement) {
            InsertStatement insertStatement = (InsertStatement) statement;
            generate(insertStatement);
            return;
        }
        if (statement instanceof MergeStatement) {
            MergeStatement mergeStatement = (MergeStatement) statement;
            generate(mergeStatement);
            return;
        }
        if (statement instanceof OpenStatement) {
            OpenStatement openStatement = (OpenStatement) statement;
            generate(openStatement);
            return;
        }
        if (statement instanceof PrepareStatement) {
            PrepareStatement prepareStatement = (PrepareStatement) statement;
            generate(prepareStatement);
            return;
        }
        if (statement instanceof QuerySpecification) {
            QuerySpecification querySpecification = (QuerySpecification) statement;
            generate(querySpecification);
            return;
        }
        if (statement instanceof ReleaseSavepointStatement) {
            ReleaseSavepointStatement releaseSavepointStatement = (ReleaseSavepointStatement) statement;
            generate(releaseSavepointStatement);
            return;
        }
        /*if (statement instanceof ReturnStatement) {
            ReturnStatement returnStatement = (ReturnStatement) statement;
            generate(returnStatement);
            return;
        }*/
        if (statement instanceof RevokePrivilegeStatement) {
            RevokePrivilegeStatement revokePrivilegeStatement = (RevokePrivilegeStatement) statement;
            generate(revokePrivilegeStatement);
            return;
        }
        if (statement instanceof RevokeRoleStatement) {
            RevokeRoleStatement revokeRoleStatement = (RevokeRoleStatement) statement;
            generate(revokeRoleStatement);
            return;
        }
        if (statement instanceof RollbackStatement) {
            RollbackStatement rollbackStatement = (RollbackStatement) statement;
            generate(rollbackStatement);
            return;
        }
        if (statement instanceof SavepointStatement) {
            SavepointStatement savepointStatement = (SavepointStatement) statement;
            generate(savepointStatement);
            return;
        }
        if (statement instanceof SchemaDefinition) {
            SchemaDefinition schemaDefinition = (SchemaDefinition) statement;
            generate(schemaDefinition);
            return;
        }
        if (statement instanceof SchemaFunction) {
            SchemaFunction schemaFunction = (SchemaFunction) statement;
            generate(schemaFunction);
            return;
        }
        if (statement instanceof SchemaProcedure) {
            SchemaProcedure schemaProcedure = (SchemaProcedure) statement;
            generate(schemaProcedure);
            return;
        }
        if (statement instanceof SetCatalogStatement) {
            SetCatalogStatement setCatalogStatement = (SetCatalogStatement) statement;
            generate(setCatalogStatement);
            return;
        }
        if (statement instanceof SetConnectionStatement) {
            SetConnectionStatement setConnectionStatement = (SetConnectionStatement) statement;
            generate(setConnectionStatement);
            return;
        }
        if (statement instanceof SetConstraintsModeStatement) {
            SetConstraintsModeStatement setConstraintsModeStatement = (SetConstraintsModeStatement) statement;
            generate(setConstraintsModeStatement);
            return;
        }
        if (statement instanceof SetDescriptorStatement) {
            SetDescriptorStatement setDescriptorStatement = (SetDescriptorStatement) statement;
            generate(setDescriptorStatement);
            return;
        }
        if (statement instanceof SetLocalTimeZoneStatement) {
            SetLocalTimeZoneStatement setLocalTimeZoneStatement = (SetLocalTimeZoneStatement) statement;
            generate(setLocalTimeZoneStatement);
            return;
        }
        if (statement instanceof SetNamesStatement) {
            SetNamesStatement setNamesStatement = (SetNamesStatement) statement;
            generate(setNamesStatement);
            return;
        }
        if (statement instanceof SetPathStatement) {
            SetPathStatement setPathStatement = (SetPathStatement) statement;
            generate(setPathStatement);
            return;
        }
        if (statement instanceof SetRoleStatement) {
            SetRoleStatement setRoleStatement = (SetRoleStatement) statement;
            generate(setRoleStatement);
            return;
        }
        if (statement instanceof SetSchemaStatement) {
            SetSchemaStatement setSchemaStatement = (SetSchemaStatement) statement;
            generate(setSchemaStatement);
            return;
        }
        if (statement instanceof SetSessionCharacteristicsStatement) {
            SetSessionCharacteristicsStatement setSessionCharacteristicsStatement = (SetSessionCharacteristicsStatement) statement;
            generate(setSessionCharacteristicsStatement);
            return;
        }
        if (statement instanceof SetSessionCollationStatementSubtype1) {
            SetSessionCollationStatementSubtype1 setSessionCollationStatementSubtype1 = (SetSessionCollationStatementSubtype1) statement;
            generate(setSessionCollationStatementSubtype1);
            return;
        }
        if (statement instanceof SetSessionCollationStatementSubtype2) {
            SetSessionCollationStatementSubtype2 setSessionCollationStatementSubtype2 = (SetSessionCollationStatementSubtype2) statement;
            generate(setSessionCollationStatementSubtype2);
            return;
        }
        if (statement instanceof SetSessionUserIdentifierStatement) {
            SetSessionUserIdentifierStatement setSessionUserIdentifierStatement = (SetSessionUserIdentifierStatement) statement;
            generate(setSessionUserIdentifierStatement);
            return;
        }
        if (statement instanceof SetTransactionStatement) {
            SetTransactionStatement setTransactionStatement = (SetTransactionStatement) statement;
            generate(setTransactionStatement);
            return;
        }
        if (statement instanceof SetTransformGroupStatement) {
            SetTransformGroupStatement setTransformGroupStatement = (SetTransformGroupStatement) statement;
            generate(setTransformGroupStatement);
            return;
        }
        /*if (statement instanceof StartTransactionStatement) {
            StartTransactionStatement startTransactionStatement
                    = (StartTransactionStatement) statement;
            generate(startTransactionStatement);
            return;
        }*/
        if (statement instanceof TableDefinition) {
            TableDefinition tableDefinition = (TableDefinition) statement;
            generate(tableDefinition);
            return;
        }
        if (statement instanceof TransliterationDefinition) {
            TransliterationDefinition transliterationDefinition = (TransliterationDefinition) statement;
            generate(transliterationDefinition);
            return;
        }
        if (statement instanceof TriggerDefinition) {
            TriggerDefinition triggerDefinition = (TriggerDefinition) statement;
            generate(triggerDefinition);
            return;
        }
        /*if (statement instanceof TriggeredSqlStatement) {
            TriggeredSqlStatement triggeredSqlStatement = (TriggeredSqlStatement) statement;
            generate(triggeredSqlStatement);
            return;
        }*/
        if (statement instanceof UpdateStatement) {
            UpdateStatement updateStatement = (UpdateStatement) statement;
            generate(updateStatement);
            return;
        }
        if (statement instanceof ViewDefinition) {
            ViewDefinition viewDefinition = (ViewDefinition) statement;
            generate(viewDefinition);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), statement.getBeginIndex(), "This statement is not supported, " + statement.getClass().getName());
    }

    // <allocate cursor statement> ::= ALLOCATE <extended cursor name> <cursor intent>
    private void generate(AllocateCursorStatement allocateCursorStatement) {
        append(TokenType.ALLOCATE.getContent());
        append(' ');
        ExtendedCursorName extendedCursorName = allocateCursorStatement.getExtendedCursorName();
        generate(extendedCursorName);
        append(' ');
        generate(allocateCursorStatement.getCursorIntent());
    }

    // [ <scope option> ] <simple value specification>
    private void generate(ExtendedCursorName extendedCursorName) {
        ScopeOption scopeOption = extendedCursorName.getScopeOption();
        if (scopeOption != null) {
            generate(scopeOption);
            append(' ');
        }
        generate(extendedCursorName.getSimpleValueSpecification());
    }

    // <scope option> ::= GLOBAL | LOCAL
    private void generate(ScopeOption scopeOption) {
        if (scopeOption.isGlobal()) {
            append(TokenType.GLOBAL.getContent());
        } else if (scopeOption.isLocal()) {
            append(TokenType.LOCAL.getContent());
        } else {
            throw new YuliaException(getSql(), getLineNumber(), scopeOption.getBeginIndex(), "This scope option is not supported, " + scopeOption.getClass().getName());
        }
    }

    // <simple value specification>
    // ::= <literal>
    //   | <host parameter name>
    //   | <SQL parameter reference>
    //   | <embedded variable name>
    private void generate(SimpleValueSpecification simpleValueSpecification) {
        if (simpleValueSpecification instanceof Literal) {
            generate((Literal) simpleValueSpecification);
            return;
        }
        if (simpleValueSpecification instanceof HostParameterName) {
            generate((HostParameterName) simpleValueSpecification);
            return;
        }
        if (simpleValueSpecification instanceof IdentifierChain) {
            generate((IdentifierChain) simpleValueSpecification);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), simpleValueSpecification.getBeginIndex(), "This simple value specification is not supported, " + simpleValueSpecification.getClass().getName());
    }

    // <host parameter name> ::= <colon> <identifier>
    private void generate(HostParameterName hostParameterName) {
        append(TokenType.COLON.getContent());
        generate(hostParameterName.getIdentifier());
    }

    // <cursor intent> ::= <statement cursor> | <result set cursor>
    private void generate(CursorIntent cursorIntent) {
        if (cursorIntent instanceof StatementCursor) {
            generate((StatementCursor) cursorIntent);
            return;
        }
        if (cursorIntent instanceof ResultSetCursor) {
            generate((ResultSetCursor) cursorIntent);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), cursorIntent.getBeginIndex(), "This is not supported, " + cursorIntent.getClass().getName());
    }

    // <statement cursor>
    // ::=
    // [ <cursor sensitivity> ]
    // [ <cursor scrollability> ]
    // CURSOR
    // [ <cursor holdability> ]
    // [ <cursor returnability> ]
    // FOR
    // <extended statement name>
    private void generate(StatementCursor statementCursor) {
        CursorSensitivity cursorSensitivity = statementCursor.getCursorSensitivity();
        if (cursorSensitivity != null) {
            generate(cursorSensitivity);
            append(' ');
        }
        CursorScrollability cursorScrollability = statementCursor.getCursorScrollability();
        if (cursorScrollability != null) {
            generate(cursorScrollability);
            append(' ');
        }
        append(TokenType.CURSOR.getContent());
        append(' ');
        CursorHoldability cursorHoldability = statementCursor.getCursorHoldability();
        if (cursorHoldability != null) {
            generate(cursorHoldability);
            append(' ');
        }
        CursorReturnability cursorReturnability = statementCursor.getCursorReturnability();
        if (cursorReturnability != null) {
            generate(cursorReturnability);
            append(' ');
        }
        append(TokenType.FOR.getContent());
        append(' ');
        generate(statementCursor.getExtendedStatementName());
    }

    // <cursor sensitivity> ::= SENSITIVE | INSENSITIVE | ASENSITIVE
    private void generate(CursorSensitivity cursorSensitivity) {
        if (cursorSensitivity.isSensitive()) {
            append(TokenType.SENSITIVE.getContent());
            return;
        }
        if (cursorSensitivity.isInsensitive()) {
            append(TokenType.INSENSITIVE.getContent());
            return;
        }
        if (cursorSensitivity.isAsensitive()) {
            append(TokenType.ASENSITIVE.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), cursorSensitivity.getBeginIndex(), "This cursor sensitivity is not supported, " + cursorSensitivity.getClass().getName());
    }

    // <cursor scrollability> ::= SCROLL | NO SCROLL
    private void generate(CursorScrollability cursorScrollability) {
        if (cursorScrollability.isScroll()) {
            append(TokenType.SCROLL.getContent());
            return;
        }
        if (cursorScrollability.isNoScroll()) {
            append(TokenType.NO.getContent());
            append(' ');
            append(TokenType.SCROLL.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), cursorScrollability.getBeginIndex(), "This cursor scrollability is not supported, " + cursorScrollability.getClass().getName());
    }

    // <cursor holdability> ::= WITH HOLD | WITHOUT HOLD
    private void generate(CursorHoldability cursorHoldability) {
        if (cursorHoldability.isWithHold()) {
            append(TokenType.WITH.getContent());
            append(' ');
            append(TokenType.HOLD.getContent());
            return;
        }
        if (cursorHoldability.isWithoutHold()) {
            append(TokenType.WITHOUT.getContent());
            append(' ');
            append(TokenType.HOLD.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), cursorHoldability.getBeginIndex(), "This cursor holdability is not supported, " + cursorHoldability.getClass().getName());
    }

    // <cursor returnability> ::= WITH RETURN | WITHOUT RETURN
    private void generate(CursorReturnability cursorReturnability) {
        if (cursorReturnability.isWithReturn()) {
            append(TokenType.WITH.getContent());
            append(' ');
            append(TokenType.RETURN.getContent());
            return;
        }
        if (cursorReturnability.isWithoutReturn()) {
            append(TokenType.WITHOUT.getContent());
            append(' ');
            append(TokenType.RETURN.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), cursorReturnability.getBeginIndex(), "This cursor returnability is not supported, " + cursorReturnability.getClass().getName());
    }

    // <extended statement name> ::= [ <scope option> ] <simple value specification>
    private void generate(ExtendedStatementName extendedStatementName) {
        ScopeOption scopeOption = extendedStatementName.getScopeOption();
        if (scopeOption != null) {
            generate(scopeOption);
            append(' ');
        }
        generate(extendedStatementName.getSimpleValueSpecification());
    }

    // <result set cursor> ::= FOR PROCEDURE <specific routine designator>
    private void generate(ResultSetCursor resultSetCursor) {
        append(TokenType.FOR.getContent());
        append(' ');
        append(TokenType.PROCEDURE.getContent());
        append(' ');
        generate(resultSetCursor.getSpecificRoutineDesignator());
    }

    // <allocate descriptor statement>
    // ::=
    // ALLOCATE
    // [ SQL ]
    // DESCRIPTOR
    // <descriptor name>
    // [ WITH MAX <occurrences> ]
    private void generate(AllocateDescriptorStatement allocateDescriptorStatement) {
        append(TokenType.ALLOCATE.getContent());
        append(' ');
        if (allocateDescriptorStatement.isSql()) {
            append(TokenType.SQL.getContent());
            append(' ');
        }
        append("DESCRIPTOR");
        append(' ');
        generate(allocateDescriptorStatement.getDescriptorName());
        SimpleValueSpecification occurrences = allocateDescriptorStatement.getOccurrences();
        if (occurrences != null) {
            append(' ');
            append(TokenType.WITH.getContent());
            append(' ');
            append("MAX");
            append(' ');
            generate(occurrences);
        }
    }

    // <descriptor name> ::= [ <scope option> ] <simple value specification>
    private void generate(DescriptorName descriptorName) {
        ScopeOption scopeOption = descriptorName.getScopeOption();
        if (scopeOption != null) {
            generate(scopeOption);
            append(' ');
        }
        generate(descriptorName.getSimpleValueSpecification());
    }

    // <alter domain statement>
    // ::=
    // ALTER
    // DOMAIN
    // <domain name>
    // <alter domain action>
    private void generate(AlterDomainStatement alterDomainStatement) {
        append(TokenType.ALTER.getContent());
        append(' ');
        append("DOMAIN");
        append(' ');
        generate(alterDomainStatement.getDomainName());
        append(' ');
        generate(alterDomainStatement.getAlterDomainAction());
    }

    //  <alter domain action>
    //  ::= <set domain default clause>
    //    | <drop domain default clause>
    //    | <add domain constraint definition>
    //    | <drop domain constraint definition>
    private void generate(AlterDomainAction alterDomainAction) {
        if (alterDomainAction instanceof SetDomainDefaultClause) {
            generate((SetDomainDefaultClause) alterDomainAction);
            return;
        }
        if (alterDomainAction instanceof DropDomainDefaultClause) {
            generate((DropDomainDefaultClause) alterDomainAction);
            return;
        }
        if (alterDomainAction instanceof AddDomainConstraintDefinition) {
            generate((AddDomainConstraintDefinition) alterDomainAction);
            return;
        }
        if (alterDomainAction instanceof DropDomainConstraintDefinition) {
            generate((DropDomainConstraintDefinition) alterDomainAction);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), alterDomainAction.getBeginIndex(), "This alter domain action is not supported, " + alterDomainAction.getClass().getName());
    }

    // <set domain default clause> ::= SET <default clause>
    private void generate(SetDomainDefaultClause setDomainDefaultClause) {
        append(TokenType.SET.getContent());
        append(' ');
        generate(setDomainDefaultClause.getDefaultClause());
    }

    // <drop domain default clause> ::= DROP DEFAULT
    private void generate(DropDomainDefaultClause dropDomainDefaultClause) {
        append(TokenType.DROP.getContent());
        append(' ');
        append(TokenType.DEFAULT.getContent());
    }

    // <add domain constraint definition> ::= ADD <domain constraint>
    private void generate(AddDomainConstraintDefinition addDomainConstraintDefinition) {
        append(TokenType.ADD.getContent());
        append(' ');
        generate(addDomainConstraintDefinition.getDomainConstraint());
    }

    // <domain constraint>
    // ::=
    // [ <constraint name definition> ]
    // <check constraint definition>
    // [ <constraint characteristics> ]
    private void generate(DomainConstraint domainConstraint) {
        ConstraintNameDefinition constraintNameDefinition
                = domainConstraint.getConstraintNameDefinition();
        if (constraintNameDefinition != null) {
            generate(constraintNameDefinition);
            append(' ');
        }
        CheckConstraintDefinition checkConstraintDefinition
                = domainConstraint.getCheckConstraintDefinition();
        generate(checkConstraintDefinition);
        ConstraintCharacteristics constraintCharacteristics
                = domainConstraint.getConstraintCharacteristics();
        if (constraintCharacteristics != null) {
            append(' ');
            generate(constraintCharacteristics);
        }
    }

    // <drop domain constraint definition> ::= DROP CONSTRAINT <constraint name>
    private void generate(DropDomainConstraintDefinition dropDomainConstraintDefinition) {
        append(TokenType.DROP.getContent());
        append(' ');
        append(TokenType.CONSTRAINT.getContent());
        append(' ');
        generate(dropDomainConstraintDefinition.getConstraintName());
    }

    // <alter routine statement>
    // ::=
    // ALTER
    // <specific routine designator>
    // <alter routine characteristics>
    // <alter routine behavior>
    private void generate(AlterRoutineStatement alterRoutineStatement) {
        append(TokenType.ALTER.getContent());
        append(' ');
        generate(alterRoutineStatement.getSpecificRoutineDesignator());
        append(' ');
        generate(alterRoutineStatement.getAlterRoutineCharacteristics());
        append(' ');
        generate(alterRoutineStatement.getAlterRoutineBehavior());
    }

    // <alter routine characteristics> ::= <alter routine characteristic> ...
    private void generate(AlterRoutineCharacteristics alterRoutineCharacteristics) {
        for (int i = 0; i < alterRoutineCharacteristics.size(); i++) {
            generate(alterRoutineCharacteristics.get(i));
            if (i < alterRoutineCharacteristics.size() - 1) {
                append(' ');
            }
        }
    }

    // <alter routine characteristic>
    // ::= <language clause>
    //   | <parameter style clause>
    //   | <SQL-data access indication>
    //   | <null-call clause>
    //   | <dynamic result sets characteristic>
    //   | NAME <external routine name>
    private void generate(AlterRoutineCharacteristic alterRoutineCharacteristic) {
        if (alterRoutineCharacteristic instanceof LanguageClause) {
            generate((LanguageClause) alterRoutineCharacteristic);
            return;
        }
        if (alterRoutineCharacteristic instanceof ParameterStyleClause) {
            generate((ParameterStyleClause) alterRoutineCharacteristic);
            return;
        }
        if (alterRoutineCharacteristic instanceof SqlDataAccessIndication) {
            generate((SqlDataAccessIndication) alterRoutineCharacteristic);
            return;
        }
        if (alterRoutineCharacteristic instanceof NullCallClause) {
            generate((NullCallClause) alterRoutineCharacteristic);
            return;
        }
        if (alterRoutineCharacteristic instanceof DynamicResultSetsCharacteristic) {
            generate((DynamicResultSetsCharacteristic) alterRoutineCharacteristic);
            return;
        }
        if (alterRoutineCharacteristic instanceof NameExternalRoutineName) {
            generate((NameExternalRoutineName) alterRoutineCharacteristic);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), alterRoutineCharacteristic.getBeginIndex(), "This alter routine characteristic is not supported, " + alterRoutineCharacteristic.getClass().getName());
    }

    // <dynamic result sets characteristic> ::= DYNAMIC RESULT SETS <maximum dynamic result sets>
    private void generate(DynamicResultSetsCharacteristic dynamicResultSetsCharacteristic) {
        append(TokenType.DYNAMIC.getContent());
        append(' ');
        append("RESULT");
        append(' ');
        append("SETS");
        append(' ');
        generate(dynamicResultSetsCharacteristic.getMaximumDynamicResultSets());
    }

    // NAME <external routine name>
    private void generate(NameExternalRoutineName nameExternalRoutineName) {
        append("NAME");
        append(' ');
        generate(nameExternalRoutineName.getExternalRoutineName());
    }

    // <alter routine behavior> ::= RESTRICT
    private void generate(AlterRoutineBehavior alterRoutineBehavior) {
        append("RESTRICT");
    }

    // <alter sequence generator statement>
    // ::=
    // ALTER
    // SEQUENCE
    // <sequence generator name>
    // <alter sequence generator options>
    private void generate(AlterSequenceGeneratorStatement alterSequenceGeneratorStatement) {
        append(TokenType.ALTER.getContent());
        append(' ');
        append("SEQUENCE");
        append(' ');
        generate(alterSequenceGeneratorStatement.getSequenceGeneratorName());
        append(' ');
        generate(alterSequenceGeneratorStatement.getAlterSequenceGeneratorOptions());
    }

    // <alter sequence generator options> ::= <alter sequence generator option> ...
    private void generate(AlterSequenceGeneratorOptions alterSequenceGeneratorOptions) {
        for (int i = 0; i < alterSequenceGeneratorOptions.size(); i++) {
            generate(alterSequenceGeneratorOptions.get(i));
            if (i < alterSequenceGeneratorOptions.size() - 1) {
                append(' ');
            }
        }
    }

    // <alter sequence generator option>
    // ::= <alter sequence generator restart option>
    //   | <basic sequence generator option>
    private void generate(AlterSequenceGeneratorOption alterSequenceGeneratorOption) {
        if (alterSequenceGeneratorOption instanceof AlterSequenceGeneratorRestartOption) {
            generate((AlterSequenceGeneratorRestartOption) alterSequenceGeneratorOption);
            return;
        }
        if (alterSequenceGeneratorOption instanceof BasicSequenceGeneratorOption) {
            generate((BasicSequenceGeneratorOption) alterSequenceGeneratorOption);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), alterSequenceGeneratorOption.getBeginIndex(), "This alter sequence generator option is not supported, " + alterSequenceGeneratorOption.getClass().getName());
    }

    // <alter table statement> ::= ALTER TABLE <table name> <alter table action>
    private void generate(AlterTableStatement alterTableStatement) {
        append(TokenType.ALTER.getContent());
        append(' ');
        append(TokenType.TABLE.getContent());
        append(' ');
        generate(alterTableStatement.getTableName());
        append(' ');
        generate(alterTableStatement.getAlterTableAction());
    }

    // <alter table action>
    // ::= <add column definition>
    //   | <alter column definition>
    //   | <drop column definition>
    //   | <add table constraint definition>
    //   | <drop table constraint definition>
    private void generate(AlterTableAction alterTableAction) {
        if (alterTableAction instanceof AddColumnDefinition) {
            generate((AddColumnDefinition) alterTableAction);
            return;
        }
        if (alterTableAction instanceof AlterColumnDefinition) {
            generate((AlterColumnDefinition) alterTableAction);
            return;
        }
        if (alterTableAction instanceof DropColumnDefinition) {
            generate((DropColumnDefinition) alterTableAction);
            return;
        }
        if (alterTableAction instanceof AddTableConstraintDefinition) {
            generate((AddTableConstraintDefinition) alterTableAction);
            return;
        }
        if (alterTableAction instanceof DropTableConstraintDefinition) {
            generate((DropTableConstraintDefinition) alterTableAction);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), alterTableAction.getBeginIndex(), "This alter table action is not supported, " + alterTableAction.getClass().getName());
    }

    // <add column definition> ::= ADD [ COLUMN ] <column definition>
    private void generate(AddColumnDefinition addColumnDefinition) {
        append(TokenType.ADD.getContent());
        append(' ');
        append(TokenType.COLUMN.getContent());
        append(' ');
        generate(addColumnDefinition.getColumnDefinition());
    }

    // <column definition>
    // ::=
    // <column name>
    // [ <data type> | <domain name> ]
    // [ <reference scope check> ]
    // [ <default clause> | <identity column specification> | <generation clause> ]
    // [ <column constraint definition> ... ]
    // [ <collate clause> ]
    private void generate(ColumnDefinition columnDefinition) {
        generate(columnDefinition.getColumnName());
        DataType dataType = columnDefinition.getDataType();
        if (dataType != null) {
            append(' ');
            generate(dataType);
        } else {
            SchemaQualifiedName domainName = columnDefinition.getDomainName();
            if (domainName != null) {
                append(' ');
                generate(domainName);
            }
        }
        ReferenceScopeCheck referenceScopeCheck = columnDefinition.getReferenceScopeCheck();
        if (referenceScopeCheck != null) {
            append(' ');
            generate(referenceScopeCheck);
        }
        DefaultClause defaultClause = columnDefinition.getDefaultClause();
        if (defaultClause != null) {
            append(' ');
            generate(defaultClause);
        } else {
            IdentityColumnSpecification identityColumnSpecification
                    = columnDefinition.getIdentityColumnSpecification();
            if (identityColumnSpecification != null) {
                append(' ');
                generate(identityColumnSpecification);
            } else {
                GenerationClause generationClause = columnDefinition.getGenerationClause();
                if (generationClause != null) {
                    append(' ');
                    generate(generationClause);
                }
            }
        }
        ColumnConstraintDefinitionList columnConstraintDefinitionList
                = columnDefinition.getColumnConstraintDefinitionList();
        if (columnConstraintDefinitionList != null) {
            append(' ');
            generate(columnConstraintDefinitionList);
        }
        CollateClause collateClause = columnDefinition.getCollateClause();
        if (collateClause != null) {
            append(' ');
            generate(collateClause);
        }
    }

    // <column constraint definition> ...
    private void generate(ColumnConstraintDefinitionList columnConstraintDefinitionList) {
        for (int i = 0; i < columnConstraintDefinitionList.size(); i++) {
            generate(columnConstraintDefinitionList.get(i));
            if (i < columnConstraintDefinitionList.size() - 1) {
                append(' ');
            }
        }
    }

    // <data type>
    // ::= <predefined type>
    //   | <row type>
    //   | <path-resolved user-defined type name>
    //   | <reference type>
    //   | <collection type>
    private void generate(DataType dataType) {
        if (dataType instanceof PredefinedType) {
            generate((PredefinedType) dataType);
            return;
        }
        if (dataType instanceof RowType) {
            generate((RowType) dataType);
            return;
        }
        if (dataType instanceof SchemaQualifiedName) {
            generate((SchemaQualifiedName) dataType);
            return;
        }
        if (dataType instanceof ReferenceType) {
            generate((ReferenceType) dataType);
            return;
        }
        if (dataType instanceof CollectionType) {
            generate((CollectionType) dataType);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), dataType.getBeginIndex(), "This data type is not supported, " + dataType.getClass().getName());
    }

    // <predefined type>
    // ::= <character string type> [ CHARACTER SET <character set specification> ] [ <collate clause> ]
    //   | <national character string type> [ <collate clause> ]
    //   | <binary large object string type>
    //   | <numeric type>
    //   | <boolean type>
    //   | <datetime type>
    //   | <interval type>
    private void generate(PredefinedType predefinedType) {
        if (predefinedType instanceof CharStringType) {
            generate((CharStringType) predefinedType);
            return;
        }
        if (predefinedType instanceof VarcharStringType) {
            generate((VarcharStringType) predefinedType);
            return;
        }
        if (predefinedType instanceof ClobStringType) {
            generate((ClobStringType) predefinedType);
            return;
        }
        if (predefinedType instanceof NationalCharStringType) {
            generate((NationalCharStringType) predefinedType);
            return;
        }
        if (predefinedType instanceof NationalVarcharStringType) {
            generate((NationalVarcharStringType) predefinedType);
            return;
        }
        if (predefinedType instanceof NationalClobStringType) {
            generate((NationalClobStringType) predefinedType);
            return;
        }
        if (predefinedType instanceof BinaryLargeObjectStringType) {
            generate((BinaryLargeObjectStringType) predefinedType);
            return;
        }
        if (predefinedType instanceof NumericType) {
            generate((NumericType) predefinedType);
            return;
        }
        if (predefinedType instanceof BooleanType) {
            generate((BooleanType) predefinedType);
            return;
        }
        if (predefinedType instanceof DatetimeType) {
            generate((DatetimeType) predefinedType);
            return;
        }
        if (predefinedType instanceof IntervalType) {
            generate((IntervalType) predefinedType);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), predefinedType.getBeginIndex(), "This predefined type is not supported, " + predefinedType.getClass().getName());
    }

    // { CHARACTER | CHAR }
    // [ <left paren> <length> <right paren> ]
    // [ CHARACTER SET <character set specification> ]
    // [ <collate clause> ]
    private void generate(CharStringType charStringType) {
        append(TokenType.CHAR.getContent());
        UnsignedInteger length = charStringType.getLength();
        if (length != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(length);
            append(TokenType.RIGHT_PAREN.getContent());
        }
        CharacterSetName characterSetSpecification
                = charStringType.getCharacterSetSpecification();
        if (characterSetSpecification != null) {
            append(' ');
            append(TokenType.CHARACTER.getContent());
            append(' ');
            append(TokenType.SET.getContent());
            append(' ');
            generate(characterSetSpecification);
        }
        CollateClause collateClause = charStringType.getCollateClause();
        if (collateClause != null) {
            append(' ');
            generate(collateClause);
        }
    }

    // {  CHARACTER VARYING | CHAR VARYING VARCHAR }
    // [ <left paren> <length> <right paren> ]
    // [ CHARACTER SET <character set specification> ]
    // [ <collate clause> ]
    private void generate(VarcharStringType varcharStringType) {
        append(TokenType.VARCHAR.getContent());
        UnsignedInteger length = varcharStringType.getLength();
        if (length != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(length);
            append(TokenType.RIGHT_PAREN.getContent());
        }
        CharacterSetName characterSetSpecification
                = varcharStringType.getCharacterSetSpecification();
        if (characterSetSpecification != null) {
            append(' ');
            append(TokenType.CHARACTER.getContent());
            append(' ');
            append(TokenType.SET.getContent());
            append(' ');
            generate(characterSetSpecification);
        }
        CollateClause collateClause = varcharStringType.getCollateClause();
        if (collateClause != null) {
            append(' ');
            generate(collateClause);
        }
    }

    // { CHARACTER LARGE OBJECT | CHAR LARGE OBJECT | CLOB }
    // [ <left paren> <length> <right paren> ]
    // [ CHARACTER SET <character set specification> ]
    // [ <collate clause> ]
    private void generate(ClobStringType clobStringType) {
        append(TokenType.CLOB.getContent());
        LargeObjectLength length = clobStringType.getLength();
        if (length != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(length);
            append(TokenType.RIGHT_PAREN.getContent());
        }
        CharacterSetName characterSetSpecification
                = clobStringType.getCharacterSetSpecification();
        if (characterSetSpecification != null) {
            append(' ');
            append(TokenType.CHARACTER.getContent());
            append(' ');
            append(TokenType.SET.getContent());
            append(' ');
            generate(characterSetSpecification);
        }
        CollateClause collateClause = clobStringType.getCollateClause();
        if (collateClause != null) {
            append(' ');
            generate(collateClause);
        }
    }

    // <large object length>
    // ::= <unsigned integer> [ <multiplier> ] [ <char length units> ]
    //   | <large object length token> [ <char length units> ]
    private void generate(LargeObjectLength largeObjectLength) {
        UnsignedInteger unsignedInteger = largeObjectLength.getUnsignedInteger();
        generate(unsignedInteger);
        Multiplier multiplier = largeObjectLength.getMultiplier();
        if (multiplier != null) {
            append(' ');
            generate(multiplier);
        }
        CharLengthUnits charLengthUnits = largeObjectLength.getCharLengthUnits();
        if (charLengthUnits != null) {
            append(' ');
            generate(charLengthUnits);
        }
    }

    // <multiplier> ::= K | M | G
    private void generate(Multiplier multiplier) {
        if (multiplier.isK()) {
            append('K');
            return;
        }
        if (multiplier.isM()) {
            append('M');
            return;
        }
        if (multiplier.isG()) {
            append('G');
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), multiplier.getBeginIndex(), "This multiplier is not supported.");
    }

    // <char length units> ::= CHARACTERS | CODE_UNITS | OCTETS
    private void generate(CharLengthUnits charLengthUnits) {
        if (charLengthUnits.isCharacters()) {
            append("CHARACTERS");
            return;
        }
        if (charLengthUnits.isCodeUnits()) {
            append("CODE_UNITS");
            return;
        }
        if (charLengthUnits.isOctets()) {
            append("OCTETS");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), charLengthUnits.getBeginIndex(), "This char length units is not supported.");
    }

    // { NATIONAL CHARACTER | NATIONAL CHAR | NCHAR }
    // [ <left paren> <length> <right paren> ]
    // [ <collate clause> ]
    private void generate(NationalCharStringType nationalCharStringType) {
        append(TokenType.NCHAR.getContent());
        UnsignedInteger length = nationalCharStringType.getLength();
        if (length != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(length);
            append(TokenType.RIGHT_PAREN.getContent());
        }
        CollateClause collateClause = nationalCharStringType.getCollateClause();
        if (collateClause != null) {
            append(' ');
            generate(collateClause);
        }
    }

    // { NATIONAL CHARACTER VARYING | NATIONAL CHAR VARYING | NCHAR VARYING }
    // <left paren> <length> <right paren>
    // [ <collate clause> ]
    private void generate(NationalVarcharStringType nationalVarcharStringType) {
        append(TokenType.NCHAR.getContent());
        append(' ');
        append(TokenType.VARYING.getContent());
        UnsignedInteger length = nationalVarcharStringType.getLength();
        if (length != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(length);
            append(TokenType.RIGHT_PAREN.getContent());
        }
        CollateClause collateClause = nationalVarcharStringType.getCollateClause();
        if (collateClause != null) {
            append(' ');
            generate(collateClause);
        }
    }

    // { NATIONAL CHARACTER LARGE OBJECT | NCHAR LARGE OBJECT | NCLOB }
    // [ <left paren> <large object length> <right paren> ]
    // [ <collate clause> ]
    private void generate(NationalClobStringType nationalClobStringType) {
        append(TokenType.NCLOB.getContent());
        LargeObjectLength length = nationalClobStringType.getLength();
        if (length != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(length);
            append(TokenType.RIGHT_PAREN.getContent());
        }
        CollateClause collateClause = nationalClobStringType.getCollateClause();
        if (collateClause != null) {
            append(' ');
            generate(collateClause);
        }
    }

    // <binary large object string type>
    // ::= BINARY LARGE OBJECT [ <left paren> <large object length> <right paren> ]
    //   | BLOB [ <left paren> <large object length> <right paren> ]
    private void generate(BinaryLargeObjectStringType binaryLargeObjectStringType) {
        append(TokenType.BLOB.getContent());
        LargeObjectLength largeObjectLength = binaryLargeObjectStringType.getLargeObjectLength();
        if (largeObjectLength != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(largeObjectLength);
            append(TokenType.RIGHT_PAREN.getContent());
        }
    }

    // <numeric type> ::= <exact numeric type> | <approximate numeric type>
    private void generate(NumericType numericType) {
        NumericTypeType numericTypeType = numericType.getNumericTypeType();
        if (numericTypeType == NumericTypeType.NUMERIC) {
            append(TokenType.NUMERIC.getContent());
        } else if (numericTypeType == NumericTypeType.DECIMAL) {
            append(TokenType.DECIMAL.getContent());
        } else if (numericTypeType == NumericTypeType.DEC) {
            append(TokenType.DEC.getContent());
        } else if (numericTypeType == NumericTypeType.SMALLINT) {
            append(TokenType.SMALLINT.getContent());
        } else if (numericTypeType == NumericTypeType.INTEGER) {
            append(TokenType.INTEGER.getContent());
        } else if (numericTypeType == NumericTypeType.INT) {
            append(TokenType.INT.getContent());
        } else if (numericTypeType == NumericTypeType.BIGINT) {
            append(TokenType.BIGINT.getContent());
        } else if (numericTypeType == NumericTypeType.FLOAT) {
            append(TokenType.FLOAT.getContent());
        } else if (numericTypeType == NumericTypeType.REAL) {
            append(TokenType.REAL.getContent());
        } else if (numericTypeType == NumericTypeType.DOUBLE_PRECISION) {
            append(TokenType.DOUBLE.getContent());
            append(' ');
            append(TokenType.PRECISION.getContent());
        } else {
            throw new YuliaException(getSql(), getLineNumber(), numericType.getBeginIndex(), "This numeric type is not supported.");
        }
        UnsignedInteger precision = numericType.getPrecision();
        if (precision != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(precision);
            UnsignedInteger scale = numericType.getScale();
            if (scale != null) {
                append(TokenType.COMMA.getContent());
                append(' ');
                generate(scale);
            }
            append(TokenType.RIGHT_PAREN.getContent());
        }
    }

    // <boolean type> ::= BOOLEAN
    private void generate(BooleanType booleanType) {
        append(TokenType.BOOLEAN.getContent());
    }

    // <datetime type>
    // ::= DATE
    //   | TIME [ <left paren> <time precision> <right paren> ] [ <with or without time zone> ]
    //   | TIMESTAMP [ <left paren> <timestamp precision> <right paren> ] [ <with or without time zone> ]
    private void generate(DatetimeType datetimeType) {
        if (datetimeType.isDate()) {
            append(TokenType.DATE.getContent());
            return;
        }
        if (datetimeType.isTime()) {
            append(TokenType.TIME.getContent());
        } else if (datetimeType.isTimestamp()) {
            append(TokenType.TIMESTAMP.getContent());
        } else {
            throw new YuliaException(getSql(), getLineNumber(), datetimeType.getBeginIndex(), "This datetime type is not supported.");
        }
        UnsignedInteger precision = datetimeType.getPrecision();
        if (precision != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(precision);
            append(TokenType.RIGHT_PAREN.getContent());
        }
        if (datetimeType.isWithTimeZone()) {
            append(' ');
            append(TokenType.WITH.getContent());
            append(' ');
            append(TokenType.TIME.getContent());
            append(' ');
            append("ZONE");
            return;
        }
        if (datetimeType.isWithoutTimeZone()) {
            append(' ');
            append(TokenType.WITHOUT.getContent());
            append(' ');
            append(TokenType.TIME.getContent());
            append(' ');
            append("ZONE");
            return;
        }
    }

    // <interval type> ::= INTERVAL <interval qualifier>
    private void generate(IntervalType intervalType) {
        append(TokenType.INTERVAL.getContent());
        append(' ');
        generate(intervalType.getIntervalQualifier());
    }

    // <row type> ::= ROW <row type body>
    private void generate(RowType rowType) {
        append(TokenType.ROW.getContent());
        append(TokenType.LEFT_PAREN.getContent());
        for (int i = 0; i < rowType.size(); i++) {
            generate(rowType.get(i));
            if (i < rowType.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <field definition> ::= <field name> <data type> [ <reference scope check> ]
    private void generate(FieldDefinition fieldDefinition) {
        generate(fieldDefinition.getFieldName());
        append(' ');
        generate(fieldDefinition.getDataType());
        ReferenceScopeCheck referenceScopeCheck
                = fieldDefinition.getReferenceScopeCheck();
        if (referenceScopeCheck != null) {
            append(' ');
            generate(referenceScopeCheck);
        }
    }

    // <reference type> ::= REF <left paren> <referenced type> <right paren> [ <scope clause> ]
    private void generate(ReferenceType referenceType) {
        append(TokenType.REF.getContent());
        append(TokenType.LEFT_PAREN.getContent());
        generate(referenceType.getReferencedType());
        append(TokenType.RIGHT_PAREN.getContent());
        ScopeClause scopeClause = referenceType.getScopeClause();
        if (scopeClause != null) {
            append(' ');
            generate(scopeClause);
        }
    }

    // <collection type> ::= <array type> | <multiset type>
    private void generate(CollectionType collectionType) {
        if (collectionType instanceof ArrayType) {
            generate((ArrayType) collectionType);
            return;
        }
        if (collectionType instanceof MultisetType) {
            generate((MultisetType) collectionType);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), collectionType.getBeginIndex(), "This collection type is not supported, " + collectionType.getClass().getName());
    }

    // <array type>
    // ::=
    // <data type>
    // ARRAY
    // [ <left bracket or trigraph> <unsigned integer> <right bracket or trigraph> ]
    private void generate(ArrayType arrayType) {
        generate(arrayType.getDataType());
        append(' ');
        append(TokenType.ARRAY.getContent());
        append(TokenType.LEFT_BRACKET.getContent());
        generate(arrayType.getUnsignedInteger());
        append(TokenType.RIGHT_BRACKET.getContent());
    }

    // <multiset type> ::= <data type> MULTISET
    private void generate(MultisetType multisetType) {
        generate(multisetType.getDataType());
        append(' ');
        append(TokenType.MULTISET.getContent());
    }

    // <reference scope check> ::= REFERENCES ARE [ NOT ] CHECKED [ ON DELETE <reference scope check action> ]
    private void generate(ReferenceScopeCheck referenceScopeCheck) {
        append(TokenType.REFERENCES.getContent());
        append(' ');
        append(TokenType.ARE.getContent());
        append(' ');
        if (referenceScopeCheck.isNot()) {
            append(TokenType.NOT.getContent());
            append(' ');
        }
        append(TokenType.CHECK.getContent());
        append(' ');
        ReferentialAction referenceScopeCheckAction = referenceScopeCheck.getReferenceScopeCheckAction();
        if (referenceScopeCheckAction != null) {
            append(TokenType.ON.getContent());
            append(' ');
            append(TokenType.DELETE.getContent());
            append(' ');
            generate(referenceScopeCheckAction);
        }
    }

    // <referential action> ::= CASCADE | SET NULL | SET DEFAULT | RESTRICT | NO ACTION
    private void generate(ReferentialAction referentialAction) {
        if (referentialAction.isCascade()) {
            append("CASCADE");
            return;
        }
        if (referentialAction.isSetNull()) {
            append(TokenType.SET.getContent());
            append(' ');
            append(TokenType.NULL.getContent());
            return;
        }
        if (referentialAction.isSetDefault()) {
            append(TokenType.SET.getContent());
            append(' ');
            append(TokenType.DEFAULT.getContent());
            return;
        }
        if (referentialAction.isRestrict()) {
            append("RESTRICT");
            return;
        }
        if (referentialAction.isNoAction()) {
            append(TokenType.NO.getContent());
            append(' ');
            append("ACTION");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), referentialAction.getBeginIndex(), "This referential action is not supported.");
    }

    // <default clause> ::= DEFAULT <default option>
    private void generate(DefaultClause defaultClause) {
        append(TokenType.DEFAULT.getContent());
        append(' ');
        generate(defaultClause.getDefaultOption());
    }

    // <default option>
    // ::= <literal>
    //   | <datetime value function>
    //   | USER
    //   | CURRENT_USER
    //   | CURRENT_ROLE
    //   | SESSION_USER
    //   | SYSTEM_USER
    //   | CURRENT_PATH
    //   | <implicitly typed value specification>
    private void generate(DefaultOption defaultOption) {
        if (defaultOption instanceof Literal) {
            generate((Literal) defaultOption);
            return;
        }
        if (defaultOption instanceof DatetimeValueFunction) {
            generate((DatetimeValueFunction) defaultOption);
            return;
        }
        if (defaultOption instanceof User) {
            append(TokenType.USER.getContent());
            return;
        }
        if (defaultOption instanceof CurrentUser) {
            append(TokenType.CURRENT_USER.getContent());
            return;
        }
        if (defaultOption instanceof CurrentRole) {
            append(TokenType.CURRENT_ROLE.getContent());
            return;
        }
        if (defaultOption instanceof SessionUser) {
            append(TokenType.SESSION_USER.getContent());
            return;
        }
        if (defaultOption instanceof SystemUser) {
            append(TokenType.SYSTEM_USER.getContent());
            return;
        }
        if (defaultOption instanceof CurrentPath) {
            append(TokenType.CURRENT_PATH.getContent());
            return;
        }
        if (defaultOption instanceof ImplicitlyTypedValueSpecification) {
            generate((ImplicitlyTypedValueSpecification) defaultOption);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), defaultOption.getBeginIndex(), "This default option is not supported, " + defaultOption.getClass().getName());
    }

    // <literal> ::= <signed numeric literal> | <general literal>
    private void generate(Literal literal) {
        if (literal instanceof SignedNumericLiteral) {
            generate((SignedNumericLiteral) literal);
            return;
        }
        if (literal instanceof GeneralLiteral) {
            generate((GeneralLiteral) literal);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), literal.getBeginIndex(), "This literal is not supported, " + literal.getClass().getName());
    }

    // <signed numeric literal> ::= [ <sign> ] <unsigned numeric literal>
    private void generate(SignedNumericLiteral signedNumericLiteral) {
        Sign sign = signedNumericLiteral.getSign();
        if (sign != null) {
            generate(sign);
        }
        generate(signedNumericLiteral.getUnsignedNumericLiteral());
    }

    // <sign> ::= <plus sign> | <minus sign>
    private void generate(Sign sign) {
        if (sign instanceof PlusSign) {
            append(TokenType.PLUS_SIGN.getContent());
            return;
        }
        if (sign instanceof MinusSign) {
            append(TokenType.MINUS_SIGN.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), sign.getBeginIndex(), "This sign is not supported, " + sign.getClass().getName());
    }

    // <unsigned numeric literal> ::= <exact numeric literal> | <approximate numeric literal>
    private void generate(UnsignedNumericLiteral unsignedNumericLiteral) {
        UnsignedInteger unsignedInteger1 = unsignedNumericLiteral.getUnsignedInteger1();
        if (unsignedInteger1 != null) {
            generate(unsignedInteger1);
        }
        UnsignedInteger unsignedInteger2 = unsignedNumericLiteral.getUnsignedInteger2();
        if (unsignedInteger2 != null) {
            append(TokenType.PERIOD.getContent());
            generate(unsignedInteger2);
        }
        SignedInteger exponent = unsignedNumericLiteral.getExponent();
        if (exponent != null) {
            append("e");
            generate(exponent);
        }
    }

    private void generate(UnsignedInteger unsignedInteger) {
        append(unsignedInteger.getContent());
    }

    // <signed integer> ::= [ <sign> ] <unsigned integer>
    private void generate(SignedInteger signedInteger) {
        Sign sign = signedInteger.getSign();
        if (sign != null) {
            generate(sign);
        }
        generate(signedInteger.getUnsignedInteger());
    }

    // <general literal>
    // ::= <character string literal>
    //   | <national character string literal>
    //   | <Unicode character string literal>
    //   | <binary string literal>
    //   | <datetime literal>
    //   | <interval literal>
    //   | <boolean literal>
    private void generate(GeneralLiteral generalLiteral) {
        if (generalLiteral instanceof CharacterStringLiteral) {
            generate((CharacterStringLiteral) generalLiteral);
            return;
        }
        if (generalLiteral instanceof NationalCharacterStringLiteral) {
            generate((NationalCharacterStringLiteral) generalLiteral);
            return;
        }
        if (generalLiteral instanceof UnicodeCharacterStringLiteral) {
            generate((UnicodeCharacterStringLiteral) generalLiteral);
            return;
        }
        if (generalLiteral instanceof BinaryStringLiteral) {
            generate((BinaryStringLiteral) generalLiteral);
            return;
        }
        if (generalLiteral instanceof DatetimeLiteral) {
            generate((DatetimeLiteral) generalLiteral);
            return;
        }
        if (generalLiteral instanceof IntervalLiteral) {
            generate((IntervalLiteral) generalLiteral);
            return;
        }
        if (generalLiteral instanceof BooleanLiteral) {
            generate((BooleanLiteral) generalLiteral);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), generalLiteral.getBeginIndex(), "This general literal is not supported, " + generalLiteral.getClass().getName());
    }

    // <national character string literal>
    // ::=
    // N <quote> [ <character representation> ... ] <quote>
    // [ { <separator> <quote> [ <character representation> ... ] <quote> }... ]
    private void generate(NationalCharacterStringLiteral nationalCharacterStringLiteral) {
        append("N");
        append(' ');
        for (int i = 0; i < nationalCharacterStringLiteral.size(); i++) {
            String s = nationalCharacterStringLiteral.get(i);
            append('\'').append(s).append('\'');
            if (i < nationalCharacterStringLiteral.size() - 1) {
                append(' ');
            }
        }
    }

    // <Unicode character string literal>
    // ::=
    // [ <introducer> <character set specification> ]
    // U <ampersand> <quote> [ <Unicode representation> ... ] <quote>
    // [ { <separator> <quote> [ <Unicode representation> ... ] <quote> }... ]
    // [ ESCAPE <escape character> ]
    private void generate(UnicodeCharacterStringLiteral unicodeCharacterStringLiteral) {
        if (unicodeCharacterStringLiteral.isIntroducer()) {
            append('_');
            append(' ');
        }
        CharacterSetName characterSetSpecification
                = unicodeCharacterStringLiteral.getCharacterSetSpecification();
        if (characterSetSpecification != null) {
            generate(characterSetSpecification);
            append(' ');
        }
        append("U");
        append(' ');
        for (int i = 0; i < unicodeCharacterStringLiteral.contentSize(); i++) {
            append('\'').append(unicodeCharacterStringLiteral.getContent(i)).append('\'');
            if (i < unicodeCharacterStringLiteral.contentSize() - 1) {
                append(' ');
            }
        }
        String escapeCharacter = unicodeCharacterStringLiteral.getEscapeCharacter();
        if (escapeCharacter != null) {
            append(' ');
            append(TokenType.ESCAPE.getContent());
            append(' ');
            append('\'').append(escapeCharacter).append('\'');
        }
    }

    // <binary string literal>
    // ::=
    // X <quote> [ { <hexit> <hexit> }... ] <quote>
    // [ { <separator> <quote> [ { <hexit> <hexit> }... ] <quote> }... ]
    // [ ESCAPE <escape character> ]
    private void generate(BinaryStringLiteral binaryStringLiteral) {
        append("X");
        append(' ');
        for (int i = 0; i < binaryStringLiteral.contentSize(); i++) {
            append('\'').append(binaryStringLiteral.getContent(i)).append('\'');
            if (i < binaryStringLiteral.contentSize() - 1) {
                append(' ');
            }
        }
        String escapeCharacter = binaryStringLiteral.getEscapeCharacter();
        if (escapeCharacter != null) {
            append(' ');
            append(TokenType.ESCAPE.getContent());
            append(' ');
            append('\'').append(escapeCharacter).append('\'');
        }
    }

    // <datetime literal> ::= <date literal> | <time literal> | <timestamp literal>
    private void generate(DatetimeLiteral datetimeLiteral) {
        if (datetimeLiteral instanceof DateLiteral) {
            generate((DateLiteral) datetimeLiteral);
            return;
        }
        if (datetimeLiteral instanceof TimeLiteral) {
            generate((TimeLiteral) datetimeLiteral);
            return;
        }
        if (datetimeLiteral instanceof TimestampLiteral) {
            generate((TimestampLiteral) datetimeLiteral);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), datetimeLiteral.getBeginIndex(), "This datetime literal is not supported, " + datetimeLiteral.getClass().getName());
    }

    // <date literal> ::= DATE <date string>
    private void generate(DateLiteral dateLiteral) {
        append(TokenType.DATE.getContent());
        append(' ');
        append('\'').append(dateLiteral.getDatetimeString()).append('\'');
    }

    // <time literal> ::= TIME <time string>
    private void generate(TimeLiteral timeLiteral) {
        append(TokenType.TIME.getContent());
        append(' ');
        append('\'').append(timeLiteral.getDatetimeString()).append('\'');
    }

    // <timestamp literal> ::= TIMESTAMP <timestamp string>
    private void generate(TimestampLiteral timestampLiteral) {
        append(TokenType.TIMESTAMP.getContent());
        append(' ');
        append('\'').append(timestampLiteral.getDatetimeString()).append('\'');
    }

    // <interval literal> ::= INTERVAL [ <sign> ] <interval string> <interval qualifier>
    private void generate(IntervalLiteral intervalLiteral) {
        append(TokenType.INTERVAL.getContent());
        append(' ');
        Sign sign = intervalLiteral.getSign();
        if (sign != null) {
            generate(sign);
            append(' ');
        }
        append('\'');
        append(intervalLiteral.getIntervalString());
        append('\'');
        append(' ');
        generate(intervalLiteral.getIntervalQualifier());
    }

    // <interval qualifier>
    // ::= <start field> TO <end field>
    //   | <single datetime field>
    private void generate(IntervalQualifier intervalQualifier) {
        if (intervalQualifier instanceof StartFieldToEndField) {
            generate((StartFieldToEndField) intervalQualifier);
            return;
        }
        if (intervalQualifier instanceof SingleDatetimeField) {
            generate((SingleDatetimeField) intervalQualifier);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), intervalQualifier.getBeginIndex(), "This interval qualifier is not supported, " + intervalQualifier.getClass().getName());
    }

    // <start field> TO <end field>
    private void generate(StartFieldToEndField startFieldToEndField) {
        generate(startFieldToEndField.getStartField());
        append(' ');
        append(TokenType.TO.getContent());
        append(' ');
        generate(startFieldToEndField.getEndField());
    }

    // <start field>
    // ::=
    // <non-second primary datetime field>
    // [ <left paren> <interval leading field precision> <right paren> ]
    private void generate(StartField startField) {
        generate(startField.getNonSecondPrimaryDatetimeField());
        UnsignedInteger intervalLeadingFieldPrecision
                = startField.getIntervalLeadingFieldPrecision();
        if (intervalLeadingFieldPrecision != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(intervalLeadingFieldPrecision);
            append(TokenType.RIGHT_PAREN.getContent());
        }
    }

    // <non-second primary datetime field> ::= YEAR | MONTH | DAY | HOUR | MINUTE
    private void generate(NonSecondPrimaryDatetimeField nonSecondPrimaryDatetimeField) {
        if (nonSecondPrimaryDatetimeField.isYear()) {
            append(TokenType.YEAR.getContent());
            return;
        }
        if (nonSecondPrimaryDatetimeField.isMonth()) {
            append(TokenType.MONTH.getContent());
            return;
        }
        if (nonSecondPrimaryDatetimeField.isDay()) {
            append(TokenType.DAY.getContent());
            return;
        }
        if (nonSecondPrimaryDatetimeField.isHour()) {
            append(TokenType.HOUR.getContent());
            return;
        }
        if (nonSecondPrimaryDatetimeField.isMinute()) {
            append(TokenType.MINUTE.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), nonSecondPrimaryDatetimeField.getBeginIndex(), "This non-second primary datetime field is not supported.");
    }

    // <end field>
    // ::= <non-second primary datetime field>
    //   | SECOND [ <left paren> <interval fractional seconds precision> <right paren> ]
    private void generate(EndField endField) {
        NonSecondPrimaryDatetimeField nonSecondPrimaryDatetimeField
                = endField.getNonSecondPrimaryDatetimeField();
        if (nonSecondPrimaryDatetimeField != null) {
            generate(nonSecondPrimaryDatetimeField);
            return;
        }
        append(TokenType.SECOND.getContent());
        UnsignedInteger intervalFractionalSecondsPrecision
                = endField.getIntervalFractionalSecondsPrecision();
        if (intervalFractionalSecondsPrecision == null) {
            return;
        }
        append(TokenType.LEFT_PAREN.getContent());
        generate(intervalFractionalSecondsPrecision);
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <single datetime field>
    // ::= <non-second primary datetime field> [ <left paren> <interval leading field precision> <right paren> ]
    //   | SECOND [ <left paren> <interval leading field precision> [ <comma> <interval fractional seconds precision> ] <right paren> ]
    private void generate(SingleDatetimeField singleDatetimeField) {
        NonSecondPrimaryDatetimeField nonSecondPrimaryDatetimeField
                = singleDatetimeField.getNonSecondPrimaryDatetimeField();
        if (nonSecondPrimaryDatetimeField != null) {
            generate(nonSecondPrimaryDatetimeField);
            UnsignedInteger intervalLeadingFieldPrecision
                    = singleDatetimeField.getIntervalLeadingFieldPrecision();
            if (intervalLeadingFieldPrecision != null) {
                append(TokenType.LEFT_PAREN.getContent());
                generate(intervalLeadingFieldPrecision);
                append(TokenType.RIGHT_PAREN.getContent());
            }
            return;
        }
        append(TokenType.SECOND.getContent());
        UnsignedInteger intervalLeadingFieldPrecision
                = singleDatetimeField.getIntervalLeadingFieldPrecision();
        if (intervalLeadingFieldPrecision == null) {
            return;
        }
        append(TokenType.LEFT_PAREN.getContent());
        generate(intervalLeadingFieldPrecision);
        UnsignedInteger intervalFractionalSecondsPrecision
                = singleDatetimeField.getIntervalFractionalSecondsPrecision();
        if (intervalFractionalSecondsPrecision != null) {
            append(TokenType.COMMA.getContent());
            append(' ');
            generate(intervalFractionalSecondsPrecision);
        }
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <boolean literal> ::= TRUE | FALSE | UNKNOWN
    private void generate(BooleanLiteral booleanLiteral) {
        if (booleanLiteral.isTrue()) {
            append(TokenType.TRUE.getContent());
            return;
        }
        if (booleanLiteral.isFalse()) {
            append(TokenType.FALSE.getContent());
            return;
        }
        if (booleanLiteral.isUnknown()) {
            append(TokenType.UNKNOWN.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), booleanLiteral.getBeginIndex(), "This boolean literal is not supported.");
    }

    // <datetime value function>
    // ::= <current date value function>
    //   | <current time value function>
    //   | <current timestamp value function>
    //   | <current local time value function>
    //   | <current local timestamp value function>
    private void generate(DatetimeValueFunction datetimeValueFunction) {
        if (datetimeValueFunction instanceof CurrentDateValueFunction) {
            generate((CurrentDateValueFunction) datetimeValueFunction);
            return;
        }
        if (datetimeValueFunction instanceof CurrentTimeValueFunction) {
            generate((CurrentTimeValueFunction) datetimeValueFunction);
            return;
        }
        if (datetimeValueFunction instanceof CurrentTimestampValueFunction) {
            generate((CurrentTimestampValueFunction) datetimeValueFunction);
            return;
        }
        if (datetimeValueFunction instanceof CurrentLocalTimeValueFunction) {
            generate((CurrentLocalTimeValueFunction) datetimeValueFunction);
            return;
        }
        if (datetimeValueFunction instanceof CurrentLocalTimestampValueFunction) {
            generate((CurrentLocalTimestampValueFunction) datetimeValueFunction);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), datetimeValueFunction.getBeginIndex(), "This datetime value function is not supported, " + datetimeValueFunction.getClass().getName());
    }

    // <current date value function> ::= CURRENT_DATE
    private void generate(CurrentDateValueFunction currentDateValueFunction) {
        append(TokenType.CURRENT_DATE.getContent());
    }

    // <current time value function> ::= CURRENT_TIME [ <left paren> <time precision> <right paren> ]
    private void generate(CurrentTimeValueFunction currentTimeValueFunction) {
        append(TokenType.CURRENT_TIME.getContent());
        UnsignedInteger timePrecision = currentTimeValueFunction.getTimePrecision();
        if (timePrecision != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(timePrecision);
            append(TokenType.RIGHT_PAREN.getContent());
        }
    }

    // <current timestamp value function> ::= CURRENT_TIMESTAMP [ <left paren> <timestamp precision> <right paren> ]
    private void generate(CurrentTimestampValueFunction currentTimestampValueFunction) {
        append(TokenType.CURRENT_TIMESTAMP.getContent());
        UnsignedInteger timestampPrecision = currentTimestampValueFunction.getTimestampPrecision();
        if (timestampPrecision != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(timestampPrecision);
            append(TokenType.RIGHT_PAREN.getContent());
        }
    }

    // <current local time value function> ::= LOCALTIME [ <left paren> <time precision> <right paren> ]
    private void generate(CurrentLocalTimeValueFunction currentLocalTimeValueFunction) {
        append(TokenType.LOCALTIME.getContent());
        UnsignedInteger timePrecision = currentLocalTimeValueFunction.getTimePrecision();
        if (timePrecision != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(timePrecision);
            append(TokenType.RIGHT_PAREN.getContent());
        }
    }

    // <current local timestamp value function> ::= LOCALTIMESTAMP [ <left paren> <timestamp precision> <right paren> ]
    private void generate(CurrentLocalTimestampValueFunction currentLocalTimestampValueFunction) {
        append(TokenType.LOCALTIMESTAMP.getContent());
        UnsignedInteger timestampPrecision = currentLocalTimestampValueFunction.getTimestampPrecision();
        if (timestampPrecision != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(timestampPrecision);
            append(TokenType.RIGHT_PAREN.getContent());
        }
    }

    // <implicitly typed value specification> ::= <null specification> | <empty specification>
    private void generate(ImplicitlyTypedValueSpecification implicitlyTypedValueSpecification) {
        if (implicitlyTypedValueSpecification.isNull()) {
            append(TokenType.NULL.getContent());
            return;
        }
        if (implicitlyTypedValueSpecification.isArray()) {
            append(TokenType.ARRAY.getContent());
            append(TokenType.LEFT_BRACKET.getContent());
            append(TokenType.RIGHT_BRACKET.getContent());
            return;
        }
        if (implicitlyTypedValueSpecification.isMultiset()) {
            append(TokenType.MULTISET.getContent());
            append(TokenType.LEFT_BRACKET.getContent());
            append(TokenType.RIGHT_BRACKET.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), implicitlyTypedValueSpecification.getBeginIndex(), "This implicitly typed value specification is not supported.");
    }

    // <identity column specification>
    // ::=
    // GENERATED
    // { ALWAYS | BY DEFAULT }
    // AS IDENTITY
    // [ <left paren> <common sequence generator options> <right paren> ]
    private void generate(IdentityColumnSpecification identityColumnSpecification) {
        append("GENERATED");
        append(' ');
        if (identityColumnSpecification.isAlways()) {
            append("ALWAYS");
            append(' ');
        } else if (identityColumnSpecification.isByDefault()) {
            append(TokenType.BY.getContent());
            append(' ');
            append(TokenType.DEFAULT.getContent());
            append(' ');
        } else {
            throw new YuliaException(getSql(), getLineNumber(), identityColumnSpecification.getBeginIndex(), "This must be GENERATED ALWAYS or GENERATED BY DEFAULT.");
        }
        append(TokenType.AS.getContent());
        append(' ');
        append(TokenType.IDENTITY.getContent());
        CommonSequenceGeneratorOptions commonSequenceGeneratorOptions
                = identityColumnSpecification.getCommonSequenceGeneratorOptions();
        if (commonSequenceGeneratorOptions != null) {
            append(' ');
            append(TokenType.LEFT_PAREN.getContent());
            generate(commonSequenceGeneratorOptions);
            append(TokenType.RIGHT_PAREN.getContent());
        }
    }

    // <common sequence generator options> ::= <common sequence generator option> ...
    private void generate(CommonSequenceGeneratorOptions commonSequenceGeneratorOptions) {
        for (int i = 0; i < commonSequenceGeneratorOptions.size(); i++) {
            generate(commonSequenceGeneratorOptions.get(i));
            if (i < commonSequenceGeneratorOptions.size() - 1) {
                append(' ');
            }
        }
    }

    // <common sequence generator option>
    // ::= <sequence generator start with option>
    //   | <basic sequence generator option>
    private void generate(CommonSequenceGeneratorOption commonSequenceGeneratorOption) {
        if (commonSequenceGeneratorOption instanceof SequenceGeneratorStartWithOption) {
            generate((SequenceGeneratorStartWithOption) commonSequenceGeneratorOption);
            return;
        }
        if (commonSequenceGeneratorOption instanceof BasicSequenceGeneratorOption) {
            generate((BasicSequenceGeneratorOption) commonSequenceGeneratorOption);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), commonSequenceGeneratorOption.getBeginIndex(), "This common sequence generator option is not supported, " + commonSequenceGeneratorOption.getClass().getName());
    }

    // <sequence generator start with option> ::= START WITH <sequence generator start value>
    private void generate(SequenceGeneratorStartWithOption sequenceGeneratorStartWithOption) {
        append(TokenType.START.getContent());
        append(' ');
        append(TokenType.WITH.getContent());
        append(' ');
        generate(sequenceGeneratorStartWithOption.getSequenceGeneratorStartValue());
    }

    // <generation clause> ::= <generation rule> AS <generation expression>
    private void generate(GenerationClause generationClause) {
        append("GENERATED");
        append(' ');
        append("ALWAYS");
        append(' ');
        generate(generationClause.getGenerationExpression());
    }

    // <column constraint definition>
    // ::=
    // [ <constraint name definition> ]
    // <column constraint>
    // [ <constraint characteristics> ]
    private void generate(ColumnConstraintDefinition columnConstraintDefinition) {
        ConstraintNameDefinition constraintNameDefinition
                = columnConstraintDefinition.getConstraintNameDefinition();
        if (constraintNameDefinition != null) {
            generate(constraintNameDefinition);
            append(' ');
        }
        generate(columnConstraintDefinition.getColumnConstraint());
        ConstraintCharacteristics constraintCharacteristics
                = columnConstraintDefinition.getConstraintCharacteristics();
        if (constraintCharacteristics != null) {
            append(' ');
            generate(constraintCharacteristics);
        }
    }

    // <column constraint>
    // ::= NOT NULL
    //   | <unique specification>
    //   | <references specification>
    //   | <check constraint definition>
    private void generate(ColumnConstraint columnConstraint) {
        if (columnConstraint instanceof NotNull) {
            generate((NotNull) columnConstraint);
            return;
        }
        if (columnConstraint instanceof UniqueSpecification) {
            generate((UniqueSpecification) columnConstraint);
            return;
        }
        if (columnConstraint instanceof ReferencesSpecification) {
            generate((ReferencesSpecification) columnConstraint);
            return;
        }
        if (columnConstraint instanceof CheckConstraintDefinition) {
            generate((CheckConstraintDefinition) columnConstraint);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), columnConstraint.getBeginIndex(), "This column constraint is not supported, " + columnConstraint.getClass().getName());
    }

    // NOT NULL
    private void generate(NotNull notNull) {
        append(TokenType.NOT.getContent());
        append(' ');
        append(TokenType.NULL.getContent());
    }

    // <collate clause> ::= COLLATE <collation name>
    private void generate(CollateClause collateClause) {
        append(TokenType.COLLATE.getContent());
        append(' ');
        generate(collateClause.getCollationName());
    }

    // <alter column definition> ::= ALTER [ COLUMN ] <column name> <alter column action>
    private void generate(AlterColumnDefinition alterColumnDefinition) {
        append(TokenType.ALTER.getContent());
        append(' ');
        if (alterColumnDefinition.isColumn()) {
            append(TokenType.COLUMN.getContent());
            append(' ');
        }
        generate(alterColumnDefinition.getColumnName());
        append(' ');
        generate(alterColumnDefinition.getAlterColumnAction());
    }

    // <alter column action>
    // ::= <set column default clause>
    //   | <drop column default clause>
    //   | <add column scope clause>
    //   | <drop column scope clause>
    //   | <alter identity column specification>
    private void generate(AlterColumnAction alterColumnAction) {
        if (alterColumnAction instanceof SetColumnDefaultClause) {
            generate((SetColumnDefaultClause) alterColumnAction);
            return;
        }
        if (alterColumnAction instanceof DropColumnDefaultClause) {
            generate((DropColumnDefaultClause) alterColumnAction);
            return;
        }
        if (alterColumnAction instanceof AddColumnScopeClause) {
            generate((AddColumnScopeClause) alterColumnAction);
            return;
        }
        if (alterColumnAction instanceof DropColumnScopeClause) {
            generate((DropColumnScopeClause) alterColumnAction);
            return;
        }
        if (alterColumnAction instanceof AlterIdentityColumnSpecification) {
            generate((AlterIdentityColumnSpecification) alterColumnAction);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), alterColumnAction.getBeginIndex(), "This alter column action is not supported, " + alterColumnAction.getClass().getName());
    }

    // <set column default clause> ::= SET <default clause>
    private void generate(SetColumnDefaultClause setColumnDefaultClause) {
        append(TokenType.SET.getContent());
        append(' ');
        generate(setColumnDefaultClause.getDefaultClause());
    }

    // <drop column default clause> ::= DROP DEFAULT
    private void generate(DropColumnDefaultClause dropColumnDefaultClause) {
        append(TokenType.DROP.getContent());
        append(' ');
        append(TokenType.DEFAULT.getContent());
    }

    // <add column scope clause> ::= ADD <scope clause>
    private void generate(AddColumnScopeClause addColumnScopeClause) {
        append(TokenType.ADD.getContent());
        append(' ');
        generate(addColumnScopeClause.getScopeClause());
    }

    // <scope clause> ::= SCOPE <table name>
    private void generate(ScopeClause scopeClause) {
        append("SCOPE");
        append(' ');
        generate(scopeClause.getTableName());
    }

    // <drop column scope clause> ::= DROP SCOPE <drop behavior>
    private void generate(DropColumnScopeClause dropColumnScopeClause) {
        append(TokenType.DROP.getContent());
        append(' ');
        append("SCOPE");
        append(' ');
        generate(dropColumnScopeClause.getDropBehavior());
    }

    // <alter identity column specification> ::= <alter identity column option> ...
    private void generate(AlterIdentityColumnSpecification alterIdentityColumnSpecification) {
        for (int i = 0; i < alterIdentityColumnSpecification.size(); i++) {
            generate(alterIdentityColumnSpecification.get(i));
            if (i < alterIdentityColumnSpecification.size() - 1) {
                append(' ');
            }
        }
    }

    // <alter identity column option>
    // ::= <alter sequence generator restart option>
    //   | SET <basic sequence generator option>
    private void generate(AlterIdentityColumnOption alterIdentityColumnOption) {
        if (alterIdentityColumnOption instanceof AlterSequenceGeneratorRestartOption) {
            generate((AlterSequenceGeneratorRestartOption) alterIdentityColumnOption);
            return;
        }
        if (alterIdentityColumnOption instanceof SetBasicSequenceGeneratorOption) {
            generate((SetBasicSequenceGeneratorOption) alterIdentityColumnOption);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), alterIdentityColumnOption.getBeginIndex(), "This alter identity column option is not supported, " + alterIdentityColumnOption.getClass().getName());
    }

    // <alter sequence generator restart option> ::= RESTART WITH <sequence generator restart value>
    private void generate(AlterSequenceGeneratorRestartOption alterSequenceGeneratorRestartOption) {
        append("RESTART");
        append(' ');
        append(TokenType.WITH.getContent());
        append(' ');
        generate(alterSequenceGeneratorRestartOption.getSequenceGeneratorRestartValue());
    }

    // SET <basic sequence generator option>
    private void generate(SetBasicSequenceGeneratorOption setBasicSequenceGeneratorOption) {
        append(TokenType.SET.getContent());
        append(' ');
        generate(setBasicSequenceGeneratorOption.getBasicSequenceGeneratorOption());
    }

    // <basic sequence generator option>
    // ::= <sequence generator increment by option>
    //   | <sequence generator maxvalue option>
    //   | <sequence generator minvalue option>
    //   | <sequence generator cycle option>
    private void generate(BasicSequenceGeneratorOption basicSequenceGeneratorOption) {
        if (basicSequenceGeneratorOption instanceof SequenceGeneratorIncrementByOption) {
            generate((SequenceGeneratorIncrementByOption) basicSequenceGeneratorOption);
            return;
        }
        if (basicSequenceGeneratorOption instanceof SequenceGeneratorMaxvalueOption) {
            generate((SequenceGeneratorMaxvalueOption) basicSequenceGeneratorOption);
            return;
        }
        if (basicSequenceGeneratorOption instanceof SequenceGeneratorMinvalueOption) {
            generate((SequenceGeneratorMinvalueOption) basicSequenceGeneratorOption);
            return;
        }
        if (basicSequenceGeneratorOption instanceof SequenceGeneratorCycleOption) {
            generate((SequenceGeneratorCycleOption) basicSequenceGeneratorOption);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), basicSequenceGeneratorOption.getBeginIndex(), "This basic sequence generator option is not supported, " + basicSequenceGeneratorOption.getClass().getName());
    }

    // <sequence generator increment by option> ::= INCREMENT BY <sequence generator increment>
    private void generate(SequenceGeneratorIncrementByOption sequenceGeneratorIncrementByOption) {
        append("INCREMENT");
        append(' ');
        append(TokenType.BY.getContent());
        append(' ');
        generate(sequenceGeneratorIncrementByOption.getSequenceGeneratorIncrement());
    }

    // <sequence generator maxvalue option>
    // ::= MAXVALUE <sequence generator max value>
    //   | NO MAXVALUE
    private void generate(SequenceGeneratorMaxvalueOption sequenceGeneratorMaxvalueOption) {
        if (sequenceGeneratorMaxvalueOption.isNo()) {
            append(TokenType.NO.getContent());
            append(' ');
            append("MAXVALUE");
            return;
        }
        append("MAXVALUE");
        append(' ');
        generate(sequenceGeneratorMaxvalueOption.getSequenceGeneratorMaxValue());
    }

    // <sequence generator minvalue option> ::= MINVALUE <sequence generator min value> | NO MINVALUE
    private void generate(SequenceGeneratorMinvalueOption sequenceGeneratorMinvalueOption) {
        if (sequenceGeneratorMinvalueOption.isNo()) {
            append(TokenType.NO.getContent());
            append(' ');
            append("MINVALUE");
            return;
        }
        append("MINVALUE");
        append(' ');
        generate(sequenceGeneratorMinvalueOption.getSequenceGeneratorMinValue());
    }

    // <sequence generator cycle option> ::= CYCLE | NO CYCLE
    private void generate(SequenceGeneratorCycleOption sequenceGeneratorCycleOption) {
        if (sequenceGeneratorCycleOption.isNo()) {
            append(TokenType.NO.getContent());
            append(' ');
        }
        append(TokenType.CYCLE.getContent());
    }

    // <drop column definition> ::= DROP [ COLUMN ] <column name> <drop behavior>
    private void generate(DropColumnDefinition dropColumnDefinition) {
        append(TokenType.DROP.getContent());
        append(' ');
        if (dropColumnDefinition.isColumn()) {
            append(TokenType.COLUMN.getContent());
            append(' ');
        }
        generate(dropColumnDefinition.getColumnName());
        append(' ');
        generate(dropColumnDefinition.getDropBehavior());
    }

    // <add table constraint definition> ::= ADD <table constraint definition>
    private void generate(AddTableConstraintDefinition addTableConstraintDefinition) {
        append(TokenType.ADD.getContent());
        append(' ');
        generate(addTableConstraintDefinition.getTableConstraintDefinition());
    }

    // <table constraint definition>
    // ::=
    // [ <constraint name definition> ]
    // <table constraint>
    // [ <constraint characteristics> ]
    private void generate(TableConstraintDefinition tableConstraintDefinition) {
        ConstraintNameDefinition constraintNameDefinition
                = tableConstraintDefinition.getConstraintNameDefinition();
        if (constraintNameDefinition != null) {
            generate(constraintNameDefinition);
            append(' ');
        }
        generate(tableConstraintDefinition.getTableConstraint());
        ConstraintCharacteristics constraintCharacteristics
                = tableConstraintDefinition.getConstraintCharacteristics();
        if (constraintCharacteristics != null) {
            append(' ');
            generate(constraintCharacteristics);
        }
    }

    // <constraint name definition> ::= CONSTRAINT <constraint name>
    private void generate(ConstraintNameDefinition constraintNameDefinition) {
        append(TokenType.CONSTRAINT.getContent());
        append(' ');
        generate(constraintNameDefinition.getConstraintName());
    }

    // <table constraint>
    // ::= <unique constraint definition>
    //   | <referential constraint definition>
    //   | <check constraint definition>
    private void generate(TableConstraint tableConstraint) {
        if (tableConstraint instanceof UniqueConstraintDefinition) {
            generate((UniqueConstraintDefinition) tableConstraint);
            return;
        }
        if (tableConstraint instanceof ReferentialConstraintDefinition) {
            generate((ReferentialConstraintDefinition) tableConstraint);
            return;
        }
        if (tableConstraint instanceof CheckConstraintDefinition) {
            generate((CheckConstraintDefinition) tableConstraint);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), tableConstraint.getBeginIndex(), "This table constraint is not supported, " + tableConstraint.getClass().getName());
    }

    // <unique constraint definition>
    // ::= <unique specification> <left paren> <unique column list> <right paren>
    //   | UNIQUE ( VALUE )
    private void generate(UniqueConstraintDefinition uniqueConstraintDefinition) {
        if (uniqueConstraintDefinition.isValue()) {
            append(TokenType.UNIQUE.getContent());
            append(' ');
            append(TokenType.VALUE.getContent());
            return;
        }
        generate(uniqueConstraintDefinition.getUniqueSpecification());
        append(' ');
        append(TokenType.LEFT_PAREN.getContent());
        generate(uniqueConstraintDefinition.getUniqueColumnList());
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <unique specification> ::= UNIQUE | PRIMARY KEY
    private void generate(UniqueSpecification uniqueSpecification) {
        if (uniqueSpecification.isUnique()) {
            append(TokenType.UNIQUE.getContent());
            return;
        }
        if (uniqueSpecification.isPrimaryKey()) {
            append(TokenType.PRIMARY.getContent());
            append(' ');
            append("KEY");
        }
        throw new YuliaException(getSql(), getLineNumber(), uniqueSpecification.getBeginIndex(), "This unique specification is not supported.");
    }

    // <referential constraint definition>
    // ::=
    // FOREIGN KEY
    // <left paren> <referencing columns> <right paren>
    // <references specification>
    private void generate(ReferentialConstraintDefinition referentialConstraintDefinition) {
        append(TokenType.FOREIGN.getContent());
        append(' ');
        append("KEY");
        append(TokenType.LEFT_PAREN.getContent());
        generate(referentialConstraintDefinition.getReferencingColumns());
        append(TokenType.RIGHT_PAREN.getContent());
        append(' ');
        generate(referentialConstraintDefinition.getReferencesSpecification());
    }

    // <references specification> ::= REFERENCES <referenced table and columns> [ MATCH <match type> ] [ <referential triggered action> ]
    private void generate(ReferencesSpecification referencesSpecification) {
        append(TokenType.REFERENCES.getContent());
        append(' ');
        generate(referencesSpecification.getReferencedTableAndColumns());
        MatchType matchType = referencesSpecification.getMatchType();
        if (matchType != null) {
            append(' ');
            append(TokenType.MATCH.getContent());
            append(' ');
            generate(matchType);
        }
        ReferentialTriggeredAction referentialTriggeredAction
                = referencesSpecification.getReferentialTriggeredAction();
        if (referentialTriggeredAction != null) {
            append(' ');
            generate(referentialTriggeredAction);
        }
    }

    // <referenced table and columns> ::= <table name> [ <left paren> <reference column list> <right paren> ]
    private void generate(ReferencedTableAndColumns referencedTableAndColumns) {
        generate(referencedTableAndColumns.getTableName());
        IdentifierList referenceColumnList = referencedTableAndColumns.getReferenceColumnList();
        if (referenceColumnList != null && !referenceColumnList.isEmpty()) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(referenceColumnList);
            append(TokenType.RIGHT_PAREN.getContent());
        }
    }

    // <match type> ::= FULL | PARTIAL | SIMPLE
    private void generate(MatchType matchType) {
        if (matchType.isFull()) {
            append(TokenType.FULL.getContent());
            return;
        }
        if (matchType.isPartial()) {
            append("PARTIAL");
            return;
        }
        if (matchType.isSimple()) {
            append("SIMPLE");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), matchType.getBeginIndex(), "This match type is not supported.");
    }

    // <referential triggered action>
    // ::= <update rule> [ <delete rule> ]
    //   | <delete rule> [ <update rule> ]
    private void generate(ReferentialTriggeredAction referentialTriggeredAction) {
        DeleteRule deleteRule = referentialTriggeredAction.getDeleteRule();
        if (deleteRule != null) {
            generate(deleteRule);
            UpdateRule updateRule = referentialTriggeredAction.getUpdateRule();
            if (updateRule != null) {
                append(' ');
                generate(updateRule);
            }
        }
        UpdateRule updateRule = referentialTriggeredAction.getUpdateRule();
        if (updateRule != null) {
            generate(updateRule);
            DeleteRule deleteRule1 = referentialTriggeredAction.getDeleteRule();
            if (deleteRule1 != null) {
                append(' ');
                generate(deleteRule1);
            }
        }
        throw new YuliaException(getSql(), getLineNumber(), referentialTriggeredAction.getBeginIndex(), "This referential triggered action is not supported.");
    }

    // <delete rule> ::= ON DELETE <referential action>
    private void generate(DeleteRule deleteRule) {
        append(TokenType.ON.getContent());
        append(' ');
        append(TokenType.DELETE.getContent());
        append(' ');
        generate(deleteRule.getReferentialAction());
    }

    // <update rule> ::= ON UPDATE <referential action>
    private void generate(UpdateRule updateRule) {
        append(TokenType.ON.getContent());
        append(' ');
        append(TokenType.UPDATE.getContent());
        append(' ');
        generate(updateRule.getReferentialAction());
    }

    // <check constraint definition>
    // ::=
    // CHECK
    // <left paren> <search condition> <right paren>
    private void generate(CheckConstraintDefinition checkConstraintDefinition) {
        append(TokenType.CHECK.getContent());
        append(TokenType.LEFT_PAREN.getContent());
        generate(checkConstraintDefinition.getSearchCondition());
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <constraint characteristics>
    // ::= <constraint check time> [ [ NOT ] DEFERRABLE ]
    //   | [ NOT ] DEFERRABLE [ <constraint check time> ]
    private void generate(ConstraintCharacteristics constraintCharacteristics) {
        generate(constraintCharacteristics.getConstraintCheckTime());
        if (constraintCharacteristics.isNot()) {
            append(' ');
            append(TokenType.NOT.getContent());
            append(' ');
            append("DEFERRABLE");
            return;
        }
        if (constraintCharacteristics.isDeferrable()) {
            append(' ');
            append("DEFERRABLE");
        }
    }

    // <constraint check time> ::= INITIALLY DEFERRED | INITIALLY IMMEDIATE
    private void generate(ConstraintCheckTime constraintCheckTime) {
        append("INITIALLY");
        append(' ');
        if (constraintCheckTime.isDeferred()) {
            append("DEFERRED");
            return;
        }
        if (constraintCheckTime.isImmediate()) {
            append(TokenType.IMMEDIATE.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), constraintCheckTime.getBeginIndex(), "This constraint check time is not supported.");
    }

    // <drop table constraint definition> ::= DROP CONSTRAINT <constraint name> <drop behavior>
    private void generate(DropTableConstraintDefinition dropTableConstraintDefinition) {
        append(TokenType.DROP.getContent());
        append(' ');
        append(TokenType.CONSTRAINT.getContent());
        append(' ');
        generate(dropTableConstraintDefinition.getConstraintName());
        append(' ');
        generate(dropTableConstraintDefinition.getDropBehavior());
    }

    // <alter type statement>
    // ::=
    // ALTER
    // TYPE
    // <schema-resolved user-defined type name>
    // <alter type action>
    private void generate(AlterTypeStatement alterTypeStatement) {
        append(TokenType.ALTER.getContent());
        append(' ');
        append("TYPE");
        append(' ');
        generate(alterTypeStatement.getSchemaResolvedUserDefinedTypeName());
        append(' ');
        generate(alterTypeStatement.getAlterTypeAction());
    }

    // <alter type action>
    // ::= <add attribute definition>
    //   | <drop attribute definition>
    //   | <add original method specification>
    //   | <add overriding method specification>
    //   | <drop method specification>
    private void generate(AlterTypeAction alterTypeAction) {
        if (alterTypeAction instanceof AddAttributeDefinition) {
            generate((AddAttributeDefinition) alterTypeAction);
            return;
        }
        if (alterTypeAction instanceof DropAttributeDefinition) {
            generate((DropAttributeDefinition) alterTypeAction);
            return;
        }
        if (alterTypeAction instanceof AddOriginalMethodSpecification) {
            generate((AddOriginalMethodSpecification) alterTypeAction);
            return;
        }
        if (alterTypeAction instanceof AddOverridingMethodSpecification) {
            generate((AddOverridingMethodSpecification) alterTypeAction);
            return;
        }
        if (alterTypeAction instanceof DropMethodSpecification) {
            generate((DropMethodSpecification) alterTypeAction);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), alterTypeAction.getBeginIndex(), "This alter type action is not supported, " + alterTypeAction.getClass().getName());
    }

    // <add attribute definition> ::= ADD ATTRIBUTE <attribute definition>
    private void generate(AddAttributeDefinition addAttributeDefinition) {
        append(TokenType.ADD.getContent());
        append(' ');
        append("ATTRIBUTE");
        append(' ');
        generate(addAttributeDefinition.getAttributeDefinition());
    }

    // <attribute definition>
    // ::=
    // <attribute name>
    // <data type>
    // [ <reference scope check> ]
    // [ <attribute default> ]
    // [ <collate clause> ]
    private void generate(AttributeDefinition attributeDefinition) {
        generate(attributeDefinition.getAttributeName());
        append(' ');
        generate(attributeDefinition.getDataType());
        ReferenceScopeCheck referenceScopeCheck
                = attributeDefinition.getReferenceScopeCheck();
        if (referenceScopeCheck != null) {
            append(' ');
            generate(referenceScopeCheck);
        }
        DefaultClause attributeDefault = attributeDefinition.getAttributeDefault();
        if (attributeDefault != null) {
            append(' ');
            generate(attributeDefault);
        }
        CollateClause collateClause = attributeDefinition.getCollateClause();
        if (collateClause != null) {
            append(' ');
            generate(collateClause);
        }
    }

    // <drop attribute definition> ::= DROP ATTRIBUTE <attribute name> RESTRICT
    private void generate(DropAttributeDefinition dropAttributeDefinition) {
        append(TokenType.DROP.getContent());
        append(' ');
        append("ATTRIBUTE");
        append(' ');
        generate(dropAttributeDefinition.getAttributeName());
        append(' ');
        append("RESTRICT");
    }

    // <add original method specification> ::= ADD <original method specification>
    private void generate(AddOriginalMethodSpecification addOriginalMethodSpecification) {
        append(TokenType.ADD.getContent());
        append(' ');
        generate(addOriginalMethodSpecification.getOriginalMethodSpecification());
    }

    // <original method specification>
    // ::=
    // <partial method specification>
    // [ SELF AS RESULT ]
    // [ SELF AS LOCATOR ]
    // [ <method characteristics> ]
    private void generate(OriginalMethodSpecification originalMethodSpecification) {
        generate(originalMethodSpecification.getPartialMethodSpecification());
        if (originalMethodSpecification.isSelfAsResult()) {
            append(' ');
            append("SELF");
            append(' ');
            append(TokenType.AS.getContent());
            append(' ');
            append("RESULT");
        }
        if (originalMethodSpecification.isSelfAsLocator()) {
            append(' ');
            append("SELF");
            append(' ');
            append(TokenType.AS.getContent());
            append(' ');
            append("LOCATOR");
        }
        MethodCharacteristics methodCharacteristics
                = originalMethodSpecification.getMethodCharacteristics();
        if (methodCharacteristics != null) {
            append(' ');
            generate(methodCharacteristics);
        }
    }

    // <partial method specification>
    // ::=
    // [ INSTANCE | STATIC | CONSTRUCTOR ]
    // METHOD
    // <method name>
    // <SQL parameter declaration list>
    // <returns clause>
    // [ SPECIFIC <specific method name> ]
    private void generate(PartialMethodSpecification partialMethodSpecification) {
        if (partialMethodSpecification.isInstance()) {
            append("INSTANCE");
        } else if (partialMethodSpecification.isStatic()) {
            append(TokenType.STATIC.getContent());
        } else if (partialMethodSpecification.isConstructor()) {
            append("CONSTRUCTOR");
        } else {
            throw new YuliaException(getSql(), getLineNumber(), partialMethodSpecification.getBeginIndex(), "Missing INSTANCE, STATIC or CONSTRUCTOR.");
        }
        append(' ');
        append(TokenType.METHOD.getContent());
        append(' ');
        generate(partialMethodSpecification.getSqlParameterDeclarationList());
        append(' ');
        generate(partialMethodSpecification.getReturnsClause());
        SchemaQualifiedName specificMethodName = partialMethodSpecification.getSpecificMethodName();
        if (specificMethodName != null) {
            append(' ');
            append(TokenType.SPECIFIC.getContent());
            append(' ');
            generate(specificMethodName);
        }
    }

    // <SQL parameter declaration list>
    // ::=
    // <left paren>
    // [ <SQL parameter declaration> [ { <comma> <SQL parameter declaration> }... ] ]
    // <right paren>
    private void generate(SqlParameterDeclarationList sqlParameterDeclarationList) {
        append(TokenType.LEFT_PAREN.getContent());
        for (int i = 0; i < sqlParameterDeclarationList.size(); i++) {
            generate(sqlParameterDeclarationList.get(i));
            if (i < sqlParameterDeclarationList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <SQL parameter declaration>
    // ::=
    // [ <parameter mode> ]
    // [ <SQL parameter name> ]
    // <parameter type>
    // [ RESULT ]
    private void generate(SqlParameterDeclaration sqlParameterDeclaration) {
        ParameterMode parameterMode = sqlParameterDeclaration.getParameterMode();
        if (parameterMode != null) {
            generate(sqlParameterDeclaration.getParameterMode());
            append(' ');
        }
        Identifier parameterName = sqlParameterDeclaration.getSqlParameterName();
        if (parameterName != null) {
            generate(parameterName);
            append(' ');
        }
        generate(sqlParameterDeclaration.getParameterType());
        if (sqlParameterDeclaration.isResult()) {
            append(' ');
            append("RESULT");
        }
    }

    // <parameter mode> ::= IN | OUT | INOUT
    private void generate(ParameterMode parameterMode) {
        if (parameterMode.isIn()) {
            append(TokenType.IN.getContent());
            return;
        }
        if (parameterMode.isOut()) {
            append(TokenType.OUT.getContent());
            return;
        }
        if (parameterMode.isInout()) {
            append(TokenType.INOUT.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), parameterMode.getBeginIndex(), "Missing IN, OUT or INOUT.");
    }

    // <parameter type> ::= <data type> [ <locator indication> ]
    private void generate(ParameterType parameterType) {
        generate(parameterType.getDataType());
        LocatorIndication locatorIndication = parameterType.getLocatorIndication();
        if (locatorIndication != null) {
            append(' ');
            generate(locatorIndication);
        }
    }

    // <locator indication> ::= AS LOCATOR
    private void generate(LocatorIndication locatorIndication) {
        append(TokenType.AS.getContent());
        append(' ');
        append("LOCATOR");
    }

    // <returns clause> ::= RETURNS <returns type>
    private void generate(ReturnsClause returnsClause) {
        append(TokenType.RETURNS.getContent());
        append(' ');
        generate(returnsClause.getReturnsType());
    }

    // <returns type>
    // ::= <returns data type> [ <result cast> ]
    //   | <returns table type>
    private void generate(ReturnsType returnsType) {
        if (returnsType instanceof ReturnsDataTypeReturnsType) {
            generate((ReturnsDataTypeReturnsType) returnsType);
            return;
        }
        if (returnsType instanceof ReturnsTableType) {
            generate((ReturnsTableType) returnsType);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), returnsType.getBeginIndex(), "This returns type is not supported, " + returnsType.getClass().getName());
    }

    // <data type> [ <locator indication> ] [ <result cast> ]
    private void generate(ReturnsDataTypeReturnsType returnsDataTypeReturnsType) {
        generate(returnsDataTypeReturnsType.getDataType());
        LocatorIndication locatorIndication = returnsDataTypeReturnsType.getLocatorIndication();
        if (locatorIndication != null) {
            append(' ');
            generate(locatorIndication);
        }
        ResultCast resultCast = returnsDataTypeReturnsType.getResultCast();
        if (resultCast != null) {
            append(' ');
            generate(resultCast);
        }
    }

    // <result cast> ::= CAST FROM <result cast from type>
    private void generate(ResultCast resultCast) {
        append(TokenType.CAST.getContent());
        append(' ');
        append(TokenType.FROM.getContent());
        append(' ');
        generate(resultCast.getResultCastFromType());
    }

    // <result cast from type> ::= <data type> [ <locator indication> ]
    private void generate(ResultCastFromType resultCastFromType) {
        generate(resultCastFromType.getDataType());
        LocatorIndication locatorIndication = resultCastFromType.getLocatorIndication();
        if (locatorIndication != null) {
            append(' ');
            generate(locatorIndication);
        }
    }

    // <returns table type> ::= TABLE <table function column list>
    private void generate(ReturnsTableType returnsTableType) {
        append(TokenType.TABLE.getContent());
        append(' ');
        generate(returnsTableType.getTableFunctionColumnList());
    }

    // <table function column list>
    // ::=
    // <left paren>
    // <table function column list element> [ { <comma> <table function column list element> }... ]
    // <right paren>
    private void generate(TableFunctionColumnList tableFunctionColumnList) {
        append(TokenType.LEFT_PAREN.getContent());
        for (int i = 0; i < tableFunctionColumnList.size(); i++) {
            generate(tableFunctionColumnList.get(i));
            if (i < tableFunctionColumnList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <table function column list element> ::= <column name> <data type>
    private void generate(TableFunctionColumnListElement tableFunctionColumnListElement) {
        generate(tableFunctionColumnListElement.getColumnName());
        append(' ');
        generate(tableFunctionColumnListElement.getDataType());
    }

    // <method characteristics> ::= <method characteristic> ...
    private void generate(MethodCharacteristics methodCharacteristics) {
        for (int i = 0; i < methodCharacteristics.size(); i++) {
            generate(methodCharacteristics.get(i));
            if (i < methodCharacteristics.size() - 1) {
                append(' ');
            }
        }
    }

    // <method characteristic>
    // ::= <language clause>
    //   | <parameter style clause>
    //   | <deterministic characteristic>
    //   | <SQL-data access indication>
    //   | <null-call clause>
    private void generate(MethodCharacteristic methodCharacteristic) {
        if (methodCharacteristic instanceof LanguageClause) {
            generate((LanguageClause) methodCharacteristic);
            return;
        }
        if (methodCharacteristic instanceof ParameterStyleClause) {
            generate((ParameterStyleClause) methodCharacteristic);
            return;
        }
        if (methodCharacteristic instanceof DeterministicCharacteristic) {
            generate((DeterministicCharacteristic) methodCharacteristic);
            return;
        }
        if (methodCharacteristic instanceof SqlDataAccessIndication) {
            generate((SqlDataAccessIndication) methodCharacteristic);
            return;
        }
        if (methodCharacteristic instanceof NullCallClause) {
            generate((NullCallClause) methodCharacteristic);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), methodCharacteristic.getBeginIndex(), "This method characteristic is not supported, " + methodCharacteristic.getClass().getName());
    }

    // <language clause> ::= LANGUAGE <language name>
    // <language name> ::= ADA | C | COBOL | FORTRAN | MUMPS | PASCAL | PLI | SQL
    private void generate(LanguageClause languageClause) {
        append(TokenType.LANGUAGE.getContent());
        append(' ');
        LanguageName languageName = languageClause.getLanguageName();
        if (languageName == LanguageName.ADA) {
            append("ADA");
            return;
        }
        if (languageName == LanguageName.C) {
            append("C");
            return;
        }
        if (languageName == LanguageName.COBOL) {
            append("COBOL");
            return;
        }
        if (languageName == LanguageName.FORTRAN) {
            append("FORTRAN");
            return;
        }
        if (languageName == LanguageName.MUMPS) {
            append("MUMPS");
            return;
        }
        if (languageName == LanguageName.PASCAL) {
            append("PASCAL");
            return;
        }
        if (languageName == LanguageName.PLI) {
            append("PLI");
            return;
        }
        if (languageName == LanguageName.SQL) {
            append(TokenType.SQL.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), languageClause.getBeginIndex(), "This language name is not supported.");
    }

    // <deterministic characteristic> ::= DETERMINISTIC | NOT DETERMINISTIC
    private void generate(DeterministicCharacteristic deterministicCharacteristic) {
        if (deterministicCharacteristic.isNot()) {
            append(TokenType.NOT.getContent());
            append(' ');
        }
        append(TokenType.DETERMINISTIC.getContent());
    }

    // <SQL-data access indication>
    // ::= NO SQL
    //   | CONTAINS SQL
    //   | READS SQL DATA
    //   | MODIFIES SQL DATA
    private void generate(SqlDataAccessIndication sqlDataAccessIndication) {
        if (sqlDataAccessIndication.isNoSql()) {
            append(TokenType.NO.getContent());
            append(' ');
            append(TokenType.SQL.getContent());
            return;
        }
        if (sqlDataAccessIndication.isContainsSql()) {
            append("CONTAINS");
            append(' ');
            append(TokenType.SQL.getContent());
            return;
        }
        if (sqlDataAccessIndication.isReadsSqlData()) {
            append(TokenType.READS.getContent());
            append(' ');
            append(TokenType.SQL.getContent());
            append(' ');
            append("DATA");
            return;
        }
        if (sqlDataAccessIndication.isModifiesSqlData()) {
            append(TokenType.MODIFIES.getContent());
            append(' ');
            append(TokenType.SQL.getContent());
            append(' ');
            append("DATA");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), sqlDataAccessIndication.getBeginIndex(), "This SQL-data access indication is not supported.");
    }

    // <null-call clause>
    // ::= RETURNS NULL ON NULL INPUT
    //   | CALLED ON NULL INPUT
    private void generate(NullCallClause nullCallClause) {
        if (nullCallClause.isReturnsNullOnNullInput()) {
            append(TokenType.RETURNS.getContent());
            append(' ');
            append(TokenType.NULL.getContent());
            append(' ');
            append(TokenType.ON.getContent());
            append(' ');
            append(TokenType.NULL.getContent());
            append(' ');
            append(TokenType.INPUT.getContent());
            return;
        }
        if (nullCallClause.isCalledOnNullInput()) {
            append(TokenType.CALLED.getContent());
            append(' ');
            append(TokenType.ON.getContent());
            append(' ');
            append(TokenType.NULL.getContent());
            append(' ');
            append(TokenType.INPUT.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), nullCallClause.getBeginIndex(), "This null-call clause is not supported.");
    }

    // <add overriding method specification> ::= ADD <overriding method specification>
    private void generate(AddOverridingMethodSpecification addOverridingMethodSpecification) {
        append(TokenType.ADD.getContent());
        append(' ');
        generate(addOverridingMethodSpecification.getOverridingMethodSpecification());
    }

    // <overriding method specification> ::= OVERRIDING <partial method specification>
    private void generate(OverridingMethodSpecification overridingMethodSpecification) {
        append("OVERRIDING");
        append(' ');
        generate(overridingMethodSpecification.getPartialMethodSpecification());
    }

    // <drop method specification> ::= DROP <specific method specification designator> RESTRICT
    private void generate(DropMethodSpecification dropMethodSpecification) {
        append(TokenType.DROP.getContent());
        append(' ');
        generate(dropMethodSpecification.getSpecificMethodSpecificationDesignator());
        append(' ');
        append("RESTRICT");
    }

    // <specific method specification designator>
    // ::=
    // [ INSTANCE | STATIC | CONSTRUCTOR ]
    // METHOD
    // <method name>
    // <data type list>
    private void generate(SpecificMethodSpecificationDesignator specificMethodSpecificationDesignator) {
        if (specificMethodSpecificationDesignator.isInstance()) {
            append("INSTANCE");
            append(' ');
        } else if (specificMethodSpecificationDesignator.isStatic()) {
            append(TokenType.STATIC.getContent());
            append(' ');
        } else if (specificMethodSpecificationDesignator.isConstructor()) {
            append("CONSTRUCTOR");
            append(' ');
        }
        append(TokenType.METHOD.getContent());
        append(' ');
        generate(specificMethodSpecificationDesignator.getMethodName());
        append(' ');
        generate(specificMethodSpecificationDesignator.getDataTypeList());
    }

    // <data type list> ::= <left paren> [ <data type> [ { <comma> <data type> }... ] ] <right paren>
    private void generate(DataTypeList dataTypeList) {
        append(TokenType.LEFT_PAREN.getContent());
        for (int i = 0; i < dataTypeList.size(); i++) {
            generate(dataTypeList.get(i));
            if (i < dataTypeList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <assertion definition>
    // ::=
    // CREATE
    // ASSERTION
    // <constraint name>
    // CHECK <left paren> <search condition> <right paren>
    // [ <constraint characteristics> ]
    private void generate(AssertionDefinition assertionDefinition) {
        append(TokenType.CREATE.getContent());
        append(' ');
        append("ASSERTION");
        append(' ');
        generate(assertionDefinition.getConstraintName());
        append(' ');
        append(TokenType.CHECK.getContent());
        append(TokenType.LEFT_PAREN.getContent());
        generate(assertionDefinition.getSearchCondition());
        append(TokenType.RIGHT_PAREN.getContent());
        ConstraintCharacteristics constraintCharacteristics
                = assertionDefinition.getConstraintCharacteristics();
        if (constraintCharacteristics != null) {
            append(' ');
            generate(constraintCharacteristics);
        }
    }

    // <character set definition>
    // ::=
    // CREATE
    // CHARACTER
    // SET
    // <character set name>
    // [ AS ]
    // <character set source>
    // [ <collate clause> ]
    private void generate(CharacterSetDefinition characterSetDefinition) {
        append(TokenType.CREATE.getContent());
        append(' ');
        append(TokenType.CHARACTER.getContent());
        append(' ');
        append(TokenType.SET.getContent());
        append(' ');
        generate(characterSetDefinition.getCharacterSetName());
        append(' ');
        append(TokenType.AS.getContent());
        append(' ');
        generate(characterSetDefinition.getCharacterSetSource());
        CollateClause collateClause = characterSetDefinition.getCollateClause();
        if (collateClause != null) {
            append(' ');
            generate(collateClause);
        }
    }

    // <character set source> ::= GET <character set specification>
    private void generate(CharacterSetSource characterSetSource) {
        append(TokenType.GET.getContent());
        append(' ');
        generate(characterSetSource.getCharacterSetSpecification());
    }

    // <close statement> ::= CLOSE <cursor name>
    private void generate(CloseStatement closeStatement) {
        append(TokenType.CLOSE.getContent());
        append(' ');
        generate(closeStatement.getCursorName());
    }

    // <collation definition>
    // ::=
    // CREATE COLLATION <collation name>
    // FOR <character set specification>
    // FROM <existing collation name>
    // [ <pad characteristic> ]
    private void generate(CollationDefinition collationDefinition) {
        append(TokenType.CREATE.getContent());
        append(' ');
        append("COLLATION");
        append(' ');
        generate(collationDefinition.getCollationName());
        append(' ');
        append(TokenType.FOR.getContent());
        append(' ');
        generate(collationDefinition.getCharacterSetSpecification());
        append(' ');
        append(TokenType.FROM.getContent());
        append(' ');
        generate(collationDefinition.getExistingCollationName());
        if (collationDefinition.isNoPad()) {
            append(' ');
            append(TokenType.NO.getContent());
            append(' ');
            append("PAD");
            return;
        }
        if (collationDefinition.isPadSpace()) {
            append(' ');
            append("PAD");
            append(' ');
            append("SPACE");
        }
    }

    // <commit statement> ::= COMMIT [ WORK ] [ AND [ NO ] CHAIN ]
    private void generate(CommitStatement commitStatement) {
        append(TokenType.COMMIT.getContent());
        if (commitStatement.isWork()) {
            append(' ');
            append("WORK");
        }
        if (commitStatement.isAndChain()) {
            append(' ');
            append(TokenType.AND.getContent());
            append(' ');
            append("CHAIN");
            return;
        }
        if (commitStatement.isAndNoChain()) {
            append(' ');
            append(TokenType.AND.getContent());
            append(' ');
            append(TokenType.NO.getContent());
            append(' ');
            append("CHAIN");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), commitStatement.getBeginIndex(), "This commit statement is not supported, " + commitStatement.getClass().getName());
    }

    // <connect statement> ::= CONNECT TO <connection target>
    private void generate(ConnectStatement connectStatement) {
        append(TokenType.CONNECT.getContent());
        append(' ');
        append(TokenType.TO.getContent());
        append(' ');
        if (connectStatement.isDefault()) {
            append(TokenType.DEFAULT.getContent());
            return;
        }
        SimpleValueSpecification sqlServerName = connectStatement.getSqlServerName();
        generate(sqlServerName);
        SimpleValueSpecification connectionName = connectStatement.getConnectionName();
        if (connectionName != null) {
            append(' ');
            append(TokenType.AS.getContent());
            append(' ');
            generate(connectionName);
        }
        SimpleValueSpecification connectionUserName = connectStatement.getConnectionUserName();
        if (connectionUserName != null) {
            append(' ');
            append(TokenType.USER.getContent());
            append(' ');
            generate(connectionUserName);
        }
    }

    // <deallocate descriptor statement> ::= DEALLOCATE [ SQL ] DESCRIPTOR <descriptor name>
    private void generate(DeallocateDescriptorStatement deallocateDescriptorStatement) {
        append(TokenType.DEALLOCATE.getContent());
        append(' ');
        if (deallocateDescriptorStatement.isSql()) {
            append(TokenType.SQL.getContent());
            append(' ');
        }
        append("DESCRIPTOR");
        append(' ');
        generate(deallocateDescriptorStatement.getDescriptorName());
    }

    // <deallocate prepared statement> ::= DEALLOCATE PREPARE <SQL statement name>
    private void generate(DeallocatePreparedStatement deallocatePreparedStatement) {
        append(TokenType.DEALLOCATE.getContent());
        append(' ');
        append(TokenType.PREPARE.getContent());
        append(' ');
        generate(deallocatePreparedStatement.getSqlStatementName());
    }

    // <SQL statement name> ::= <statement name> | <extended statement name>
    private void generate(SqlStatementName sqlStatementName) {
        if (sqlStatementName instanceof Identifier) {
            generate((Identifier) sqlStatementName);
            return;
        }
        if (sqlStatementName instanceof ExtendedStatementName) {
            generate((ExtendedStatementName) sqlStatementName);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), sqlStatementName.getBeginIndex(), "This SQL statement name is not supported, " + sqlStatementName.getClass().getName());
    }

    // DECLARE <cursor name> [ <cursor sensitivity> ] [ <cursor scrollability> ] CURSOR [ <cursor holdability> ] [ <cursor returnability> ] FOR <cursor specification>
    // DECLARE <cursor name> [ <cursor sensitivity> ] [ <cursor scrollability> ] CURSOR [ <cursor holdability> ] [ <cursor returnability> ] FOR <statement name>
    private void generate(DeclareCursorStatement declareCursorStatement) {
        append(TokenType.DECLARE.getContent());
        append(' ');
        generate(declareCursorStatement.getCursorName());
        CursorSensitivity cursorSensitivity = declareCursorStatement.getCursorSensitivity();
        if (cursorSensitivity != null) {
            append(' ');
            generate(cursorSensitivity);
        }
        CursorScrollability cursorScrollability = declareCursorStatement.getCursorScrollability();
        if (cursorScrollability != null) {
            append(' ');
            generate(cursorScrollability);
        }
        append(' ');
        append(TokenType.CURSOR.getContent());
        CursorHoldability cursorHoldability = declareCursorStatement.getCursorHoldability();
        if (cursorHoldability != null) {
            append(' ');
            generate(cursorHoldability);
        }
        CursorReturnability cursorReturnability = declareCursorStatement.getCursorReturnability();
        if (cursorReturnability != null) {
            append(' ');
            generate(cursorReturnability);
        }
        append(' ');
        append(TokenType.FOR.getContent());
        append(' ');
        CursorSpecification cursorSpecification = declareCursorStatement.getCursorSpecification();
        if (cursorSpecification != null) {
            generate(cursorSpecification);
            return;
        }
        Identifier statementName = declareCursorStatement.getStatementName();
        if (statementName != null) {
            generate(statementName);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), declareCursorStatement.getBeginIndex(), "This declareCursorStatement is not supported, " + declareCursorStatement.getClass().getName());
    }

    // <local qualified name> ::= [ <local qualifier> <period> ] <qualified identifier>
    private void generate(LocalQualifiedName localQualifiedName) {
        if (localQualifiedName.isModule()) {
            append(TokenType.MODULE.getContent());
            append(' ');
        }
        generate(localQualifiedName.getQualifiedIdentifier());
    }

    // <cursor specification> ::= <query expression> [ <order by clause> ] [ <updatability clause> ]
    private void generate(CursorSpecification cursorSpecification) {
        QueryExpression queryExpression = cursorSpecification.getQueryExpression();
        generate(queryExpression);
        OrderByClause orderByClause = cursorSpecification.getOrderByClause();
        if (orderByClause != null) {
            append(' ');
            generate(orderByClause);
        }
        UpdatabilityClause updatabilityClause = cursorSpecification.getUpdatabilityClause();
        if (updatabilityClause != null) {
            append(' ');
            generate(updatabilityClause);
        }
    }

    // <order by clause> ::= ORDER BY <sort specification list>
    private void generate(OrderByClause orderByClause) {
        append(TokenType.ORDER.getContent());
        append(' ');
        append(TokenType.BY.getContent());
        append(' ');
        generate(orderByClause.getSortSpecificationList());
    }

    // <sort specification list> ::= <sort specification> [ { <comma> <sort specification> }... ]
    private void generate(SortSpecificationList sortSpecificationList) {
        for (int i = 0; i < sortSpecificationList.size(); i++) {
            SortSpecification sortSpecification = sortSpecificationList.get(i);
            generate(sortSpecification);
            if (i < sortSpecificationList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <sort specification> ::= <sort key> [ <ordering specification> ] [ <null ordering> ]
    private void generate(SortSpecification sortSpecification) {
        generate(sortSpecification.getSortKey());
        OrderingSpecification orderingSpecification = sortSpecification.getOrderingSpecification();
        if (orderingSpecification != null) {
            append(' ');
            generate(orderingSpecification);
        }
        NullOrdering nullOrdering = sortSpecification.getNullOrdering();
        if (nullOrdering != null) {
            append(' ');
            generate(nullOrdering);
        }
    }

    // <ordering specification> ::= ASC | DESC
    private void generate(OrderingSpecification orderingSpecification) {
        if (orderingSpecification.isAsc()) {
            append("ASC");
            return;
        }
        if (orderingSpecification.isDesc()) {
            append("DESC");
        }
    }

    // <null ordering> ::= NULLS FIRST | NULLS LAST
    private void generate(NullOrdering nullOrdering) {
        if (nullOrdering.isNullsFirst()) {
            append("NULLS");
            append(' ');
            append("FIRST");
            return;
        }
        if (nullOrdering.isNullsLast()) {
            append("NULLS");
            append(' ');
            append("LAST");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), nullOrdering.getBeginIndex(), "Missing NULLS FIRST or NULLS LAST.");
    }

    // <updatability clause> ::= FOR { READ ONLY | UPDATE [ OF <column name list> ] }
    private void generate(UpdatabilityClause updatabilityClause) {
        append(TokenType.FOR.getContent());
        append(' ');
        if (updatabilityClause.isReadOnly()) {
            append("READ");
            append(TokenType.ONLY.getContent());
            return;
        }
        append(TokenType.UPDATE.getContent());
        IdentifierList columnNameList = updatabilityClause.getColumnNameList();
        if (columnNameList != null) {
            append(' ');
            append(TokenType.OF.getContent());
            append(' ');
            generate(columnNameList);
        }
    }

    // <query expression> ::= [ <with clause> ] <query expression body>
    private void generate(QueryExpression queryExpression) {
        WithClause withClause = queryExpression.getWithClause();
        if (withClause != null) {
            generate(withClause);
            append(' ');
        }
        generate(queryExpression.getQueryExpressionBody());
    }

    // <query expression body> ::= <non-join query expression> | <joined table>
    private void generate(QueryExpressionBody queryExpressionBody) {
        if (queryExpressionBody instanceof NonJoinQueryExpression) {
            generate((NonJoinQueryExpression) queryExpressionBody);
            return;
        }
        if (queryExpressionBody instanceof JoinedTable) {
            generate((JoinedTable) queryExpressionBody);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), queryExpressionBody.getBeginIndex(), "This query expression body is not supported, " + queryExpressionBody.getClass().getName());
    }

    // <non-join query expression>
    // ::= <non-join query term>
    //   | <query expression body> UNION [ ALL | DISTINCT ] [ <corresponding spec> ] <query term>
    //   | <query expression body> EXCEPT [ ALL | DISTINCT ] [ <corresponding spec> ] <query term>
    private void generate(NonJoinQueryExpression nonJoinQueryExpression) {
        if (nonJoinQueryExpression instanceof NonJoinQueryTerm) {
            generate((NonJoinQueryTerm) nonJoinQueryExpression);
            return;
        }
        if (nonJoinQueryExpression instanceof UnionNonJoinQueryExpression) {
            generate((UnionNonJoinQueryExpression) nonJoinQueryExpression);
            return;
        }
        if (nonJoinQueryExpression instanceof ExceptNonJoinQueryExpression) {
            generate((ExceptNonJoinQueryExpression) nonJoinQueryExpression);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), nonJoinQueryExpression.getBeginIndex(), "This non-join query expression is not supported, " + nonJoinQueryExpression.getClass().getName());
    }

    // <non-join query term>
    // ::= <non-join query primary>
    //   | <query term> INTERSECT [ ALL | DISTINCT ] [ <corresponding spec> ] <query primary>
    private void generate(NonJoinQueryTerm nonJoinQueryTerm) {
        if (nonJoinQueryTerm instanceof NonJoinQueryPrimary) {
            generate((NonJoinQueryPrimary) nonJoinQueryTerm);
            return;
        }
        if (nonJoinQueryTerm instanceof IntersectNonJoinQueryTerm) {
            generate((IntersectNonJoinQueryTerm) nonJoinQueryTerm);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), nonJoinQueryTerm.getBeginIndex(), "This non-join query term is not supported, " + nonJoinQueryTerm.getClass().getName());
    }

    // <non-join query primary> ::= <simple table> | <left paren> <non-join query expression> <right paren>
    private void generate(NonJoinQueryPrimary nonJoinQueryPrimary) {
        if (nonJoinQueryPrimary instanceof SimpleTable) {
            generate((SimpleTable) nonJoinQueryPrimary);
            return;
        }
        if (nonJoinQueryPrimary instanceof NonJoinQueryExpressionNonJoinQueryPrimary) {
            generate((NonJoinQueryExpressionNonJoinQueryPrimary) nonJoinQueryPrimary);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), nonJoinQueryPrimary.getBeginIndex(), "This non-join query primary is not supported, " + nonJoinQueryPrimary.getClass().getName());
    }

    // <simple table>
    // ::= <query specification>
    //   | <table value constructor>
    //   | <explicit table>
    private void generate(SimpleTable simpleTable) {
        if (simpleTable instanceof QuerySpecification) {
            generate((QuerySpecification) simpleTable);
            return;
        }
        if (simpleTable instanceof TableValueConstructor) {
            generate((TableValueConstructor) simpleTable);
            return;
        }
        if (simpleTable instanceof ExplicitTable) {
            generate((ExplicitTable) simpleTable);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), simpleTable.getBeginIndex(), "This simple table is not supported, " + simpleTable.getClass().getName());
    }

    // <table value constructor> ::= VALUES <row value expression list>
    private void generate(TableValueConstructor tableValueConstructor) {
        append(TokenType.VALUES.getContent());
        append(' ');
        for (int i = 0; i < tableValueConstructor.size(); i++) {
            TableRowValueExpression tableRowValueExpression = tableValueConstructor.get(i);
            generate(tableRowValueExpression);
            if (i < tableValueConstructor.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <table row value expression>
    // ::= <row value special case>
    //   | <row value constructor>
    private void generate(TableRowValueExpression tableRowValueExpression) {
        if (tableRowValueExpression instanceof NonparenthesizedValueExpressionPrimary) {
            generate((NonparenthesizedValueExpressionPrimary) tableRowValueExpression);
            return;
        }
        if (tableRowValueExpression instanceof RowValueConstructor) {
            generate((RowValueConstructor) tableRowValueExpression);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), tableRowValueExpression.getBeginIndex(), "This table row value expression is not supported, " + tableRowValueExpression.getClass().getName());
    }

    // <row value constructor>
    // ::= <common value expression>
    //   | <boolean value expression>
    //   | <explicit row value constructor>
    private void generate(RowValueConstructor rowValueConstructor) {
        if (rowValueConstructor instanceof CommonValueExpression) {
            generate((CommonValueExpression) rowValueConstructor);
            return;
        }
        if (rowValueConstructor instanceof BooleanValueExpression) {
            generate((BooleanValueExpression) rowValueConstructor);
            return;
        }
        if (rowValueConstructor instanceof ExplicitRowValueConstructor) {
            generate((ExplicitRowValueConstructor) rowValueConstructor);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), rowValueConstructor.getBeginIndex(), "This row value constructor is not supported, " + rowValueConstructor.getClass().getName());
    }

    // <explicit table> ::= TABLE <table or query name>
    private void generate(ExplicitTable explicitTable) {
        append(TokenType.TABLE.getContent());
        append(' ');
        generate(explicitTable.getTableOrQueryName());
    }

    // <left paren> <non-join query expression> <right paren>
    private void generate(NonJoinQueryExpressionNonJoinQueryPrimary nonJoinQueryExpressionNonJoinQueryPrimary) {
        append(TokenType.LEFT_PAREN.getContent());
        generate(nonJoinQueryExpressionNonJoinQueryPrimary.getNonJoinQueryExpression());
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <query term> INTERSECT [ ALL | DISTINCT ] [ <corresponding spec> ] <query primary>
    private void generate(IntersectNonJoinQueryTerm intersectNonJoinQueryTerm) {
        QueryTerm queryTerm = intersectNonJoinQueryTerm.getQueryTerm();
        generate(queryTerm);
        append(' ');
        append(TokenType.INTERSECT.getContent());
        append(' ');
        if (intersectNonJoinQueryTerm.isAll()) {
            append(TokenType.ALL.getContent());
            append(' ');
        } else {
            append(TokenType.DISTINCT.getContent());
            append(' ');
        }
        CorrespondingSpec correspondingSpec = intersectNonJoinQueryTerm.getCorrespondingSpec();
        if (correspondingSpec != null) {
            generate(correspondingSpec);
            append(' ');
        }
        generate(intersectNonJoinQueryTerm.getQueryPrimary());
    }

    // <query term> ::= <non-join query term> | <joined table>
    private void generate(QueryTerm queryTerm) {
        if (queryTerm instanceof NonJoinQueryTerm) {
            generate((NonJoinQueryTerm) queryTerm);
            return;
        }
        if (queryTerm instanceof JoinedTable) {
            generate((JoinedTable) queryTerm);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), queryTerm.getBeginIndex(), "This query term is not supported, " + queryTerm.getClass().getName());
    }

    // <corresponding spec>
    // ::=
    // CORRESPONDING
    // [ BY <left paren> <corresponding column list> <right paren> ]
    private void generate(CorrespondingSpec correspondingSpec) {
        append(TokenType.CORRESPONDING.getContent());
        IdentifierList correspondingColumnList = correspondingSpec.getCorrespondingColumnList();
        if (correspondingColumnList != null) {
            append(' ');
            append(TokenType.BY.getContent());
            append(' ');
            append(TokenType.LEFT_PAREN.getContent());
            generate(correspondingColumnList);
            append(TokenType.RIGHT_PAREN.getContent());
        }
    }

    // <query primary> ::= <non-join query primary> | <joined table>
    private void generate(QueryPrimary queryPrimary) {
        if (queryPrimary instanceof NonJoinQueryPrimary) {
            generate((NonJoinQueryPrimary) queryPrimary);
            return;
        }
        if (queryPrimary instanceof JoinedTable) {
            generate((JoinedTable) queryPrimary);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), queryPrimary.getBeginIndex(), "This query primary is not supported, " + queryPrimary.getClass().getName());
    }

    // <query expression body> UNION [ ALL | DISTINCT ] [ <corresponding spec> ] <query term>
    private void generate(UnionNonJoinQueryExpression unionNonJoinQueryExpression) {
        generate(unionNonJoinQueryExpression.getQueryExpressionBody());
        append(' ');
        append(TokenType.UNION.getContent());
        append(' ');
        if (unionNonJoinQueryExpression.isAll()) {
            append(TokenType.ALL.getContent());
            append(' ');
        } else if (unionNonJoinQueryExpression.isDistinct()) {
            append(TokenType.DISTINCT.getContent());
            append(' ');
        }
        CorrespondingSpec correspondingSpec = unionNonJoinQueryExpression.getCorrespondingSpec();
        if (correspondingSpec != null) {
            generate(correspondingSpec);
            append(' ');
        }
        generate(unionNonJoinQueryExpression.getQueryTerm());
    }

    // <query expression body> EXCEPT [ ALL | DISTINCT ] [ <corresponding spec> ] <query term>
    private void generate(ExceptNonJoinQueryExpression exceptNonJoinQueryExpression) {
        generate(exceptNonJoinQueryExpression.getQueryExpressionBody());
        append(' ');
        append(TokenType.EXCEPT.getContent());
        append(' ');
        if (exceptNonJoinQueryExpression.isAll()) {
            append(TokenType.ALL.getContent());
            append(' ');
        } else if (exceptNonJoinQueryExpression.isDistinct()) {
            append(TokenType.DISTINCT.getContent());
            append(' ');
        }
        CorrespondingSpec correspondingSpec = exceptNonJoinQueryExpression.getCorrespondingSpec();
        if (correspondingSpec != null) {
            generate(correspondingSpec);
            append(' ');
        }
        generate(exceptNonJoinQueryExpression.getQueryTerm());
    }

    // <with clause> ::= WITH [ RECURSIVE ] <with list>
    private void generate(WithClause withClause) {
        append(TokenType.WITH.getContent());
        append(' ');
        if (withClause.isRecursive()) {
            append(TokenType.RECURSIVE.getContent());
            append(' ');
        }
        generate(withClause.getWithList());
    }

    // <with list> ::= <with list element> [ { <comma> <with list element> }... ]
    private void generate(WithList withList) {
        for (int i = 0; i < withList.size(); i++) {
            WithListElement withListElement = withList.get(i);
            generate(withListElement);
            if (i < withList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <with list element>
    // ::=
    // <query name>
    // [ <left paren> <with column list> <right paren> ]
    // AS <left paren> <query expression> <right paren>
    // [ <search or cycle clause> ]
    private void generate(WithListElement withListElement) {
        generate(withListElement.getQueryName());
        IdentifierList withColumnList = withListElement.getWithColumnList();
        if (withColumnList != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(withColumnList);
            append(TokenType.RIGHT_PAREN.getContent());
        }
        append(' ');
        append(TokenType.AS.getContent());
        append(' ');
        append(TokenType.LEFT_PAREN.getContent());
        generate(withListElement.getQueryExpression());
        append(TokenType.RIGHT_PAREN.getContent());
        SearchOrCycleClause searchOrCycleClause = withListElement.getSearchOrCycleClause();
        if (searchOrCycleClause != null) {
            append(' ');
            generate(searchOrCycleClause);
        }
    }

    // <search or cycle clause>
    // ::= <search clause>
    //   | <cycle clause>
    //   | <search clause> <cycle clause>
    private void generate(SearchOrCycleClause searchOrCycleClause) {
        SearchClause searchClause = searchOrCycleClause.getSearchClause();
        if (searchClause != null) {
            generate(searchClause);
        }
        CycleClause cycleClause = searchOrCycleClause.getCycleClause();
        if (cycleClause != null) {
            generate(cycleClause);
        }
    }

    // <search clause> ::= SEARCH <recursive search order> SET <sequence column>
    private void generate(SearchClause searchClause) {
        append(TokenType.SEARCH.getContent());
        append(' ');
        generate(searchClause.getRecursiveSearchOrder());
        append(' ');
        append(TokenType.SET.getContent());
        append(' ');
        generate(searchClause.getSequenceName());
    }

    // <recursive search order>
    // ::= DEPTH FIRST BY <sort specification list>
    //   | BREADTH FIRST BY <sort specification list>
    private void generate(RecursiveSearchOrder recursiveSearchOrder) {
        if (recursiveSearchOrder.isDepthFirstBy()) {
            append("DEPTH");
        } else if (recursiveSearchOrder.isBreadthFirstBy()) {
            append("BREADTH");
        }
        append(' ');
        append("FIRST");
        append(' ');
        append(TokenType.BY.getContent());
        append(' ');
        generate(recursiveSearchOrder.getSortSpecificationList());
    }

    // <cycle clause>
    // ::=
    // CYCLE <cycle column list>
    // SET <cycle mark column> TO <cycle mark value>
    // DEFAULT <non-cycle mark value>
    // USING <path column>
    private void generate(CycleClause cycleClause) {
        append(TokenType.CYCLE.getContent());
        append(' ');
        generate(cycleClause.getCycleColumnList());
        append(' ');
        append(TokenType.SET.getContent());
        append(' ');
        generate(cycleClause.getCycleMarkColumn());
        append(' ');
        append(TokenType.TO.getContent());
        append(' ');
        generate(cycleClause.getCycleMarkValue());
        append(' ');
        append(TokenType.DEFAULT.getContent());
        append(' ');
        generate(cycleClause.getNonCycleMarkValue());
        append(' ');
        append(TokenType.USING.getContent());
        append(' ');
        generate(cycleClause.getPathColumn());
    }

    // <delete statement: positioned> | <delete statement: searched> | <dynamic delete statement: positioned>
    private void generate(DeleteStatement deleteStatement) {
        append(TokenType.DELETE.getContent());
        append(' ');
        append(TokenType.FROM.getContent());
        append(' ');
        generate(deleteStatement.getTargetTable());
        DynamicCursorName dynamicCursorName = deleteStatement.getDynamicCursorName();
        if (dynamicCursorName != null) {
            append(TokenType.WHERE.getContent());
            append(' ');
            append(TokenType.CURRENT.getContent());
            append(' ');
            append(TokenType.OF.getContent());
            append(' ');
            generate(dynamicCursorName);
            return;
        }
        BooleanValueExpression searchCondition = deleteStatement.getSearchCondition();
        if (searchCondition != null) {
            append(TokenType.WHERE.getContent());
            append(' ');
            generate(searchCondition);
            return;
        }
    }

    // <target table>
    // ::= <table name>
    //   | ONLY <left paren> <table name> <right paren>
    private void generate(TargetTable targetTable) {
        if (targetTable.isOnly()) {
            append(TokenType.ONLY.getContent());
            append(TokenType.LEFT_PAREN.getContent());
        }
        generate(targetTable.getTableName());
        if (targetTable.isOnly()) {
            append(TokenType.RIGHT_PAREN.getContent());
        }
    }

    // <dynamic cursor name> ::= <cursor name> | <extended cursor name>
    private void generate(DynamicCursorName dynamicCursorName) {
        if (dynamicCursorName instanceof LocalQualifiedName) {
            generate((LocalQualifiedName) dynamicCursorName);
            return;
        }
        if (dynamicCursorName instanceof ExtendedCursorName) {
            generate((ExtendedCursorName) dynamicCursorName);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), dynamicCursorName.getBeginIndex(), "This dynamic cursor name is not supported, " + dynamicCursorName.getClass().getName());
    }

    // <describe input statement>
    // ::=
    // DESCRIBE INPUT <SQL statement name> <using descriptor> [ <nesting option> ]
    private void generate(DescribeInputStatement describeInputStatement) {
        append(TokenType.DESCRIBE.getContent());
        append(' ');
        append(TokenType.INPUT.getContent());
        append(' ');
        generate(describeInputStatement.getSqlStatementName());
        append(' ');
        generate(describeInputStatement.getUsingDescriptor());
        NestingOption nestingOption = describeInputStatement.getNestingOption();
        if (nestingOption != null) {
            append(' ');
            generate(nestingOption);
        }
    }

    // <nesting option> ::= WITH NESTING | WITHOUT NESTING
    private void generate(NestingOption nestingOption) {
        if (nestingOption.isWithNesting()) {
            append(TokenType.WITH.getContent());
        } else if (nestingOption.isWithoutNesting()) {
            append(TokenType.WITHOUT.getContent());
        } else {
            throw new YuliaException(getSql(), getLineNumber(), nestingOption.getBeginIndex(), "This nesting option is not supported.");
        }
        append(' ');
        append("NESTING");
    }

    // <describe output statement>
    // ::=
    // DESCRIBE [ OUTPUT ] <described object> <using descriptor> [ <nesting option> ]
    private void generate(DescribeOutputStatement describeOutputStatement) {
        append(TokenType.DESCRIBE.getContent());
        append(' ');
        if (describeOutputStatement.isOutput()) {
            append(TokenType.OUTPUT.getContent());
            append(' ');
        }
        generate(describeOutputStatement.getDescribedObject());
        append(' ');
        generate(describeOutputStatement.getUsingDescriptor());
        NestingOption nestingOption = describeOutputStatement.getNestingOption();
        if (nestingOption != null) {
            append(' ');
            generate(nestingOption);
        }
    }

    // <described object>
    // ::= <SQL statement name>
    //   | CURSOR <extended cursor name> STRUCTURE
    private void generate(DescribedObject describedObject) {
        SqlStatementName sqlStatementName = describedObject.getSqlStatementName();
        if (sqlStatementName != null) {
            generate(sqlStatementName);
            return;
        }
        ExtendedCursorName extendedCursorName = describedObject.getExtendedCursorName();
        if (extendedCursorName != null) {
            append(TokenType.CURSOR.getContent());
            append(' ');
            generate(extendedCursorName);
            append(' ');
            append("STRUCTURE");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), describedObject.getBeginIndex(), "This described object is not supported.");
    }

    // <disconnect statement> ::= DISCONNECT <disconnect object>
    private void generate(DisconnectStatement disconnectStatement) {
        append(TokenType.DISCONNECT.getContent());
        append(' ');
        generate(disconnectStatement.getDisconnectObject());
    }

    // <disconnect object> ::= <connection object> | ALL |     CURRENT
    private void generate(DisconnectObject disconnectObject) {
        ConnectionObject connectionObject = disconnectObject.getConnectionObject();
        if (connectionObject != null) {
            generate(connectionObject);
            return;
        }
        if (disconnectObject.isAll()) {
            append(TokenType.ALL.getContent());
            return;
        }
        if (disconnectObject.isCurrent()) {
            append(TokenType.CURRENT.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), disconnectObject.getBeginIndex(), "This disconnect object is not supported.");
    }

    // <connection object> ::= DEFAULT | <connection name>
    private void generate(ConnectionObject connectionObject) {
        if (connectionObject.isDefault()) {
            append(TokenType.DEFAULT.getContent());
            return;
        }
        SimpleValueSpecification connectionName
                = connectionObject.getConnectionName();
        if (connectionName != null) {
            generate(connectionName);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), connectionObject.getBeginIndex(), "This connection object is not supported.");
    }

    // <domain definition>
    // ::=
    // CREATE
    // DOMAIN
    // <domain name> [ AS ] <data type>
    // [ <default clause> ]
    // [ <domain constraint> ... ]
    // [ <collate clause> ]
    private void generate(DomainDefinition domainDefinition) {
        append(TokenType.CREATE.getContent());
        append(' ');
        append("DOMAIN");
        append(' ');
        generate(domainDefinition.getDomainName());
        append(' ');
        append(TokenType.AS.getContent());
        append(' ');
        generate(domainDefinition.getDataType());
        DefaultClause defaultClause = domainDefinition.getDefaultClause();
        if (defaultClause != null) {
            append(' ');
            generate(defaultClause);
        }
        DomainConstraintList domainConstraintList = domainDefinition.getDomainConstraintList();
        if (domainConstraintList != null) {
            append(' ');
            generate(domainConstraintList);
        }
        CollateClause collateClause = domainDefinition.getCollateClause();
        if (collateClause != null) {
            append(' ');
            generate(collateClause);
        }
    }

    // <domain constraint> ...
    private void generate(DomainConstraintList domainConstraintList) {
        for (int i = 0; i < domainConstraintList.size(); i++) {
            generate(domainConstraintList.get(i));
            if (i < domainConstraintList.size() - 1) {
                append(' ');
            }
        }
    }

    // <drop assertion statement> ::= DROP ASSERTION <constraint name>
    private void generate(DropAssertionStatement dropAssertionStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        append("ASSERTION");
        append(' ');
        generate(dropAssertionStatement.getConstraintName());
    }

    // <drop character set statement> ::= DROP CHARACTER SET <character set name>
    private void generate(DropCharacterSetStatement dropCharacterSetStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        append(TokenType.CHARACTER.getContent());
        append(' ');
        append(TokenType.SET.getContent());
        append(' ');
        generate(dropCharacterSetStatement.getCharacterSetName());
    }

    // <drop collation statement> ::= DROP COLLATION <collation name> <drop behavior>
    private void generate(DropCollationStatement dropCollationStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        append("COLLATION");
        append(' ');
        generate(dropCollationStatement.getCollationName());
        append(' ');
        generate(dropCollationStatement.getDropBehavior());
    }

    // <drop data type statement> ::= DROP TYPE <schema-resolved user-defined type name> <drop behavior>
    private void generate(DropDataTypeStatement dropDataTypeStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        append("TYPE");
        append(' ');
        generate(dropDataTypeStatement.getSchemaResolvedUserDefinedTypeName());
        append(' ');
        generate(dropDataTypeStatement.getDropBehavior());
    }

    // <drop domain statement> ::= DROP DOMAIN <domain name> <drop behavior>
    private void generate(DropDomainStatement dropDomainStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        append("DOMAIN");
        append(' ');
        generate(dropDomainStatement.getDomainName());
        append(' ');
        generate(dropDomainStatement.getDropBehavior());
    }

    // <drop role statement> ::= DROP ROLE <role name>
    private void generate(DropRoleStatement dropRoleStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        append("ROLE");
        append(' ');
        generate(dropRoleStatement.getRoleName());
    }

    // <drop routine statement> ::= DROP <specific routine designator> <drop behavior>
    private void generate(DropRoutineStatement dropRoutineStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        generate(dropRoutineStatement.getSpecificRoutineDesignator());
        append(' ');
        generate(dropRoutineStatement.getDropBehavior());
    }

    // <drop schema statement> ::= DROP SCHEMA <schema name> <drop behavior>
    private void generate(DropSchemaStatement dropSchemaStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        append("SCHEMA");
        append(' ');
        generate(dropSchemaStatement.getSchemaName());
        append(' ');
        generate(dropSchemaStatement.getDropBehavior());
    }

    // <drop sequence generator statement> ::= DROP SEQUENCE <sequence generator name> <drop behavior>
    private void generate(DropSequenceGeneratorStatement dropSequenceGeneratorStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        append("SEQUENCE");
        append(' ');
        generate(dropSequenceGeneratorStatement.getSequenceGeneratorName());
        append(' ');
        generate(dropSequenceGeneratorStatement.getDropBehavior());
    }

    // <drop table statement> ::= DROP TABLE <table name> <drop behavior>
    private void generate(DropTableStatement dropTableStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        append(TokenType.TABLE.getContent());
        append(' ');
        generate(dropTableStatement.getTableName());
        append(' ');
        generate(dropTableStatement.getDropBehavior());
    }

    // <drop transform statement>
    // ::=
    // DROP
    // { TRANSFORM | TRANSFORMS }
    // <transforms to be dropped>
    // FOR
    // <schema-resolved user-defined type name>
    // <drop behavior>
    private void generate(DropTransformStatement dropTransformStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        if (dropTransformStatement.isTransform()) {
            append("TRANSFORM");
            append(' ');
        } else if (dropTransformStatement.isTransforms()) {
            append("TRANSFORMS");
            append(' ');
        } else {
            throw new YuliaException(getSql(), getLineNumber(), dropTransformStatement.getBeginIndex(), "Missing TRANSFORM or TRANSFORMS.");
        }
        generate(dropTransformStatement.getTransformsToBeDropped());
        append(' ');
        append(TokenType.FOR.getContent());
        append(' ');
        generate(dropTransformStatement.getSchemaResolvedUserDefinedTypeName());
        append(' ');
        generate(dropTransformStatement.getDropBehavior());
    }

    // <transforms to be dropped> ::= ALL | <transform group element>
    private void generate(TransformsToBeDropped transformsToBeDropped) {
        Identifier transformGroupElement = transformsToBeDropped.getTransformGroupElement();
        if (transformGroupElement == null) {
            append(TokenType.ALL.getContent());
            return;
        }
        generate(transformGroupElement);
    }

    // <drop transliteration statement> ::= DROP TRANSLATION <transliteration name>
    private void generate(DropTransliterationStatement dropTransliterationStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        append(TokenType.TRANSLATION.getContent());
        append(' ');
        generate(dropTransliterationStatement.getTranslationName());
    }

    // <drop trigger statement> ::= DROP TRIGGER <trigger name>
    private void generate(DropTriggerStatement dropTriggerStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        append(TokenType.TRIGGER.getContent());
        append(' ');
        generate(dropTriggerStatement.getTriggerName());
    }

    // <drop user-defined cast statement>
    // ::=
    // DROP
    // CAST
    // <left paren> <source data type> AS <target data type> <right paren>
    // <drop behavior>
    private void generate(DropUserDefinedCastStatement dropUserDefinedCastStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        append(TokenType.CAST.getContent());
        append(TokenType.LEFT_PAREN.getContent());
        generate(dropUserDefinedCastStatement.getSourceDataType());
        append(' ');
        append(TokenType.AS.getContent());
        append(' ');
        generate(dropUserDefinedCastStatement.getTargetDataType());
        append(TokenType.RIGHT_PAREN.getContent());
        append(' ');
        generate(dropUserDefinedCastStatement.getDropBehavior());
    }

    // <drop user-defined ordering statement>
    // ::=
    // DROP
    // ORDERING
    // FOR
    // <schema-resolved user-defined type name>
    // <drop behavior>
    private void generate(DropUserDefinedOrderingStatement dropUserDefinedOrderingStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        append("ORDERING");
        append(' ');
        append(TokenType.FOR.getContent());
        append(' ');
        generate(dropUserDefinedOrderingStatement.getSchemaResolvedUserDefinedTypeName());
        append(' ');
        generate(dropUserDefinedOrderingStatement.getDropBehavior());
    }

    // <drop view statement> ::= DROP VIEW <table name> <drop behavior>
    private void generate(DropViewStatement dropViewStatement) {
        append(TokenType.DROP.getContent());
        append(' ');
        append("VIEW");
        append(' ');
        generate(dropViewStatement.getTableName());
        append(' ');
        generate(dropViewStatement.getDropBehavior());
    }

    // <dynamic close statement> ::= CLOSE <dynamic cursor name>
    private void generate(DynamicCloseStatement dynamicCloseStatement) {
        append(TokenType.CLOSE.getContent());
        append(' ');
        generate(dynamicCloseStatement.getDynamicCursorName());
    }

    // <dynamic delete statement: positioned>
    // ::=
    // DELETE FROM <target table>
    // WHERE CURRENT OF <dynamic cursor name>
    private void generate(DynamicDeleteStatementPositioned dynamicDeleteStatementPositioned) {
        append(TokenType.DELETE.getContent());
        append(' ');
        append(TokenType.FROM.getContent());
        append(' ');
        generate(dynamicDeleteStatementPositioned.getTargetTable());
        append(' ');
        append(TokenType.WHERE.getContent());
        append(' ');
        append(TokenType.CURRENT.getContent());
        append(' ');
        append(TokenType.OF.getContent());
        append(' ');
        generate(dynamicDeleteStatementPositioned.getDynamicCursorName());
    }

    // <dynamic fetch statement>
    // ::=
    // FETCH
    // [ [ <fetch orientation> ] FROM ]
    // <dynamic cursor name>
    // <output using clause>
    private void generate(DynamicFetchStatement dynamicFetchStatement) {
        append(TokenType.FETCH.getContent());
        append(' ');
        FetchOrientation fetchOrientation = dynamicFetchStatement.getFetchOrientation();
        if (fetchOrientation != null) {
            generate(fetchOrientation);
            append(' ');
            append(TokenType.FROM.getContent());
            append(' ');
        } else {
            if (dynamicFetchStatement.isFrom()) {
                append(TokenType.FROM.getContent());
                append(' ');
            }
        }
        generate(dynamicFetchStatement.getDynamicCursorName());
        append(' ');
        generate(dynamicFetchStatement.getOutputUsingClause());
    }

    // <dynamic open statement>
    // ::=
    // OPEN
    // <dynamic cursor name>
    // [ <input using clause> ]
    private void generate(DynamicOpenStatement dynamicOpenStatement) {
        append(TokenType.OPEN.getContent());
        append(' ');
        generate(dynamicOpenStatement.getDynamicCursorName());
        InputUsingClause inputUsingClause = dynamicOpenStatement.getInputUsingClause();
        if (inputUsingClause != null) {
            append(' ');
            generate(inputUsingClause);
        }
    }

    // <dynamic update statement: positioned>
    // ::=
    // UPDATE <target table>
    // SET <set clause list>
    // WHERE CURRENT OF <dynamic cursor name>
    private void generate(DynamicUpdateStatementPositioned dynamicUpdateStatementPositioned) {
        append(TokenType.UPDATE.getContent());
        append(' ');
        generate(dynamicUpdateStatementPositioned.getTargetTable());
        append(TokenType.SET.getContent());
        append(' ');
        generate(dynamicUpdateStatementPositioned.getSetClauseList());
        append(' ');
        append(TokenType.WHERE.getContent());
        append(' ');
        append(TokenType.CURRENT.getContent());
        append(' ');
        append(TokenType.OF.getContent());
        append(' ');
        generate(dynamicUpdateStatementPositioned.getDynamicCursorName());
    }

    // <execute immediate statement> ::= EXECUTE IMMEDIATE <SQL statement variable>
    private void generate(ExecuteImmediateStatement executeImmediateStatement) {
        append(TokenType.EXECUTE.getContent());
        append(' ');
        append(TokenType.IMMEDIATE.getContent());
        append(' ');
        generate(executeImmediateStatement.getSqlStatementVariable());
    }

    // <execute statement>
    // ::=
    // EXECUTE
    // <SQL statement name>
    // [ <result using clause> ]
    // [ <parameter using clause> ]
    private void generate(ExecuteStatement executeStatement) {
        append(TokenType.EXECUTE.getContent());
        append(' ');
        generate(executeStatement.getSqlStatementName());
        OutputUsingClause resultUsingClause
                = executeStatement.getResultUsingClause();
        if (resultUsingClause != null) {
            append(' ');
            generate(resultUsingClause);
        }
        InputUsingClause parameterUsingClause
                = executeStatement.getParameterUsingClause();
        if (parameterUsingClause != null) {
            append(' ');
            generate(parameterUsingClause);
        }
    }

    // <output using clause> ::= <into arguments> | <into descriptor>
    private void generate(OutputUsingClause outputUsingClause) {
        append(TokenType.INTO.getContent());
        append(' ');
        if (!outputUsingClause.isIntoArgumentListEmpty()) {
            for (int i = 0; i < outputUsingClause.intoArgumentListSize(); i++) {
                generate(outputUsingClause.getIntoArgument(i));
                if (i < outputUsingClause.intoArgumentListSize() - 1) {
                    append(TokenType.COMMA.getContent());
                    append(' ');
                }
            }
            return;
        }
        if (outputUsingClause.isSql()) {
            append(TokenType.SQL.getContent());
            append(' ');
        }
        append("DESCRIPTOR");
        append(' ');
        DescriptorName descriptorName = outputUsingClause.getDescriptorName();
        generate(descriptorName);
    }

    // <target specification>
    // ::= <host parameter specification>
    //   | <SQL parameter reference>
    //   | <column reference>
    //   | <target array element specification>
    //   | <dynamic parameter specification>
    //   | <embedded variable specification>
    private void generate(TargetSpecification targetSpecification) {
        if (targetSpecification instanceof HostParameterSpecification) {
            generate((HostParameterSpecification) targetSpecification);
            return;
        }
        if (targetSpecification instanceof IdentifierChain) {
            generate((IdentifierChain) targetSpecification);
            return;
        }
        if (targetSpecification instanceof ColumnReference) {
            generate((ColumnReference) targetSpecification);
            return;
        }
        if (targetSpecification instanceof TargetArrayElementSpecification) {
            generate((TargetArrayElementSpecification) targetSpecification);
            return;
        }
        if (targetSpecification instanceof DynamicParameterSpecification) {
            generate((DynamicParameterSpecification) targetSpecification);
            return;
        }
        if (targetSpecification instanceof EmbeddedVariableSpecification) {
            generate((EmbeddedVariableSpecification) targetSpecification);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), targetSpecification.getBeginIndex(), "This target specification is not supported, " + targetSpecification.getClass().getName());
    }

    // <target array element specification>
    // ::=
    // <target array reference>
    // <left bracket or trigraph>
    // <simple value specification>
    // <right bracket or trigraph>
    private void generate(TargetArrayElementSpecification targetArrayElementSpecification) {
        generate(targetArrayElementSpecification.getTargetArrayReference());
        append(TokenType.LEFT_BRACKET.getContent());
        generate(targetArrayElementSpecification.getSimpleValueSpecification());
        append(TokenType.RIGHT_BRACKET.getContent());
    }

    // <target array reference> ::= <SQL parameter reference> | <column reference>
    private void generate(TargetArrayReference targetArrayReference) {
        if (targetArrayReference instanceof IdentifierChain) {
            generate((IdentifierChain) targetArrayReference);
            return;
        }
        if (targetArrayReference instanceof ColumnReference) {
            generate((ColumnReference) targetArrayReference);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), targetArrayReference.getBeginIndex(), "This target array reference is not supported, " + targetArrayReference.getClass().getName());
    }

    // <dynamic parameter specification> ::= <question mark>
    private void generate(DynamicParameterSpecification dynamicParameterSpecification) {
        append(TokenType.QUESTION_MARK.getContent());
    }

    // <embedded variable specification> ::= <embedded variable name> [ <indicator variable> ]
    private void generate(EmbeddedVariableSpecification embeddedVariableSpecification) {
        generate(embeddedVariableSpecification.getEmbeddedVariableName());
        IndicatorVariable indicatorVariable = embeddedVariableSpecification.getIndicatorVariable();
        if (indicatorVariable != null) {
            append(' ');
            generate(indicatorVariable);
        }
    }

    // <indicator variable> ::= [ INDICATOR ] <embedded variable name>
    private void generate(IndicatorVariable indicatorVariable) {
        if (indicatorVariable.isIndicator()) {
            append(TokenType.INDICATOR.getContent());
            append(' ');
        }
        generate(indicatorVariable.getEmbeddedVariableName());
    }

    // <input using clause>
    // ::= USING <using argument> [ { <comma> <using argument> }... ]
    //   | <using descriptor>
    private void generate(InputUsingClause inputUsingClause) {
        if (!inputUsingClause.isUsingArgumentListEmpty()) {
            append(TokenType.USING.getContent());
            append(' ');
            for (int i = 0; i < inputUsingClause.usingArgumentListSize(); i++) {
                generate(inputUsingClause.getUsingArgument(i));
                if (i < inputUsingClause.usingArgumentListSize() - 1) {
                    append(TokenType.COMMA.getContent());
                    append(' ');
                }
            }
            return;
        }
        generate(inputUsingClause.getUsingDescriptor());
    }

    // <using descriptor> ::= USING [ SQL ] DESCRIPTOR <descriptor name>
    private void generate(UsingDescriptor usingDescriptor) {
        append(TokenType.USING.getContent());
        append(' ');
        if (usingDescriptor.isSql()) {
            append(TokenType.SQL.getContent());
            append(' ');
        }
        append("DESCRIPTOR");
        append(' ');
        generate(usingDescriptor.getDescriptorName());
    }

    // <fetch statement>
    // ::=
    // FETCH
    // [ [ <fetch orientation> ] FROM ]
    // <cursor name>
    // INTO
    // <fetch target list>
    private void generate(FetchStatement fetchStatement) {
        append(TokenType.FETCH.getContent());
        append(' ');
        FetchOrientation fetchOrientation = fetchStatement.getFetchOrientation();
        if (fetchOrientation != null) {
            generate(fetchOrientation);
            append(' ');
        }
        if (fetchStatement.isFrom()) {
            append(TokenType.FROM.getContent());
            append(' ');
        }
        generate(fetchStatement.getCursorName());
        append(' ');
        append(TokenType.INTO.getContent());
        append(' ');
        generate(fetchStatement.getFetchTargetList());
    }

    // <fetch orientation>
    // ::= NEXT
    //   | PRIOR
    //   | FIRST
    //   | LAST
    //   | { ABSOLUTE | RELATIVE } <simple value specification>
    private void generate(FetchOrientation fetchOrientation) {
        if (fetchOrientation.isNext()) {
            append("NEXT");
            return;
        }
        if (fetchOrientation.isPrior()) {
            append("PRIOR");
            return;
        }
        if (fetchOrientation.isFirst()) {
            append("FIRST");
            return;
        }
        if (fetchOrientation.isLast()) {
            append("LAST");
            return;
        }
        if (fetchOrientation.isAbsolute()) {
            append("ABSOLUTE");
            append(' ');
            generate(fetchOrientation.getSimpleValueSpecification());
            return;
        }
        if (fetchOrientation.isRelative()) {
            append("RELATIVE");
            append(' ');
            generate(fetchOrientation.getSimpleValueSpecification());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), fetchOrientation.getBeginIndex(), "This fetch orientation is not supported.");
    }

    // <fetch target list> ::= <target specification> [ { <comma> <target specification> }... ]
    private void generate(TargetSpecificationList targetSpecificationList) {
        for (int i = 0; i < targetSpecificationList.size(); i++) {
            generate(targetSpecificationList.get(i));
            if (i < targetSpecificationList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <free locator statement> ::= FREE LOCATOR <locator reference> [ { <comma> <locator reference> }... ]
    private void generate(FreeLocatorStatement freeLocatorStatement) {
        append("FREE");
        append(' ');
        append("LOCATOR");
        append(' ');
        generate(freeLocatorStatement.getLocatorReferenceList());
    }

    // <locator reference> [ { <comma> <locator reference> }... ]
    private void generate(LocatorReferenceList locatorReferenceList) {
        for (int i = 0; i < locatorReferenceList.size(); i++) {
            generate(locatorReferenceList.get(i));
            if (i < locatorReferenceList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <locator reference> ::= <host parameter name> | <embedded variable name>
    private void generate(LocatorReference locatorReference) {
        if (locatorReference instanceof HostParameterName) {
            generate((HostParameterName) locatorReference);
            return;
        }
        if (locatorReference instanceof EmbeddedVariableName) {
            generate((EmbeddedVariableName) locatorReference);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), locatorReference.getBeginIndex(), "This locator reference is not supported, " + locatorReference.getClass().getName());
    }

    // <embedded variable name> ::= <colon> <host identifier>
    private void generate(EmbeddedVariableName embeddedVariableName) {
        append(TokenType.COLON.getContent());
        append(' ');
        generate(embeddedVariableName.getHostIdentifier());
    }

    // <host identifier>
    // ::= <Ada host identifier>
    //   | <C host identifier>
    //   | <COBOL host identifier>
    //   | <Fortran host identifier>
    //   | <MUMPS host identifier>
    //   | <Pascal host identifier>
    //   | <PL/I host identifier>
    private void generate(HostIdentifier hostIdentifier) {
        throw new YuliaException(getSql(), getLineNumber(), hostIdentifier.getBeginIndex(), "This host identifier is not supported.");
    }

    // <get descriptor statement>
    // ::=
    // GET [ SQL ] DESCRIPTOR
    // <descriptor name>
    // <get descriptor information>
    private void generate(GetDescriptorStatement getDescriptorStatement) {
        append(TokenType.GET.getContent());
        append(' ');
        if (getDescriptorStatement.isSql()) {
            append(TokenType.SQL.getContent());
            append(' ');
        }
        append("DESCRIPTOR");
        append(' ');
        generate(getDescriptorStatement.getDescriptorName());
        append(' ');
        generate(getDescriptorStatement.getGetDescriptorInformation());
    }

    // <get descriptor information>
    // ::= <get header information> [ { <comma> <get header information> }... ]
    //   | VALUE <item number> <get item information> [ { <comma> <get item information> }... ]
    private void generate(GetDescriptorInformation getDescriptorInformation) {
        GetHeaderInformationList getHeaderInformationList
                = getDescriptorInformation.getGetHeaderInformationList();
        if (getHeaderInformationList != null) {
            for (int i = 0; i < getHeaderInformationList.size(); i++) {
                generate(getHeaderInformationList.get(i));
                if (i < getHeaderInformationList.size() - 1) {
                    append(' ');
                }
            }
            return;
        }
        SimpleValueSpecification itemNumber = getDescriptorInformation.getItemNumber();
        if (itemNumber != null) {
            append(TokenType.VALUE.getContent());
            append(' ');
            generate(itemNumber);
            append(' ');
            GetItemInformationList getItemInformationList
                    = getDescriptorInformation.getGetItemInformationList();
            for (int i = 0; i < getItemInformationList.size(); i++) {
                generate(getItemInformationList.get(i));
                if (i < getHeaderInformationList.size() - 1) {
                    append(TokenType.COMMA.getContent());
                    append(' ');
                }
            }
        }
        throw new YuliaException(getSql(), getLineNumber(), getDescriptorInformation.getBeginIndex(), "This get descriptor information is not supported.");
    }

    // <get header information>
    // ::=
    // <simple target specification 1>
    // <equals operator>
    // <header item name>
    private void generate(GetHeaderInformation getHeaderInformation) {
        generate(getHeaderInformation.getSimpleTargetSpecification1());
        append(TokenType.EQUALS_OPERATOR.getContent());
        generate(getHeaderInformation.getHeaderItemName());
    }

    // <simple target specification>
    // ::= <host parameter specification>
    //   | <SQL parameter reference>
    //   | <column reference>
    //   | <embedded variable name>
    private void generate(SimpleTargetSpecification simpleTargetSpecification) {
        if (simpleTargetSpecification instanceof HostParameterSpecification) {
            generate((HostParameterSpecification) simpleTargetSpecification);
            return;
        }
        if (simpleTargetSpecification instanceof IdentifierChain) {
            generate((IdentifierChain) simpleTargetSpecification);
            return;
        }
        if (simpleTargetSpecification instanceof ColumnReference) {
            generate((ColumnReference) simpleTargetSpecification);
            return;
        }
        if (simpleTargetSpecification instanceof EmbeddedVariableName) {
            generate((EmbeddedVariableName) simpleTargetSpecification);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), simpleTargetSpecification.getBeginIndex(), "This simple target specification is not supported, " + simpleTargetSpecification.getClass().getName());
    }

    // <host parameter specification> ::= <host parameter name> [ <indicator parameter> ]
    private void generate(HostParameterSpecification hostParameterSpecification) {
        generate(hostParameterSpecification.getHostParameterName());
        IndicatorParameter indicatorParameter = hostParameterSpecification.getIndicatorParameter();
        if (indicatorParameter != null) {
            append(' ');
            generate(indicatorParameter);
        }
    }

    // <indicator parameter> ::= [ INDICATOR ] <host parameter name>
    private void generate(IndicatorParameter indicatorParameter) {
        if (indicatorParameter.isIndicator()) {
            append(TokenType.INDICATOR.getContent());
            append(' ');
        }
        generate(indicatorParameter.getHostParameterName());
    }

    // <column reference>
    // ::= <basic identifier chain>
    //   | MODULE <period> <qualified identifier> <period> <column name>
    private void generate(ColumnReference columnReference) {
        if (columnReference instanceof IdentifierChain) {
            generate((IdentifierChain) columnReference);
            return;
        }
        if (columnReference instanceof ModuleQualifiedIdentifierColumnName) {
            generate((ModuleQualifiedIdentifierColumnName) columnReference);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), columnReference.getBeginIndex(), "This column reference is not supported, " + columnReference.getClass().getName());
    }

    // MODULE <period> <qualified identifier> <period> <column name>
    private void generate(ModuleQualifiedIdentifierColumnName moduleQualifiedIdentifierColumnName) {
        append(TokenType.MODULE.getContent());
        append(TokenType.PERIOD.getContent());
        generate(moduleQualifiedIdentifierColumnName.getQualifiedIdentifier());
        append(TokenType.PERIOD.getContent());
        generate(moduleQualifiedIdentifierColumnName.getColumnName());
    }

    // <header item name> ::= COUNT | KEY_TYPE | DYNAMIC_FUNCTION | DYNAMIC_FUNCTION_CODE | TOP_LEVEL_COUNT
    private void generate(HeaderItemName headerItemName) {
        if (headerItemName.isCount()) {
            append("COUNT");
            return;
        }
        if (headerItemName.isKeyType()) {
            append("KEY_TYPE");
            return;
        }
        if (headerItemName.isDynamicFunction()) {
            append("DYNAMIC_FUNCTION");
            return;
        }
        if (headerItemName.isDynamicFunctionCode()) {
            append("DYNAMIC_FUNCTION_CODE");
            return;
        }
        if (headerItemName.isTopLevelCount()) {
            append("TOP_LEVEL_COUNT");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), headerItemName.getBeginIndex(), "This header item name is not supported.");
    }

    // <get item information>
    // ::=
    // <simple target specification 2>
    // <equals operator>
    // <descriptor item name>
    private void generate(GetItemInformation getItemInformation) {
        generate(getItemInformation.getSimpleTargetSpecification2());
        append(TokenType.EQUALS_OPERATOR.getContent());
        generate(getItemInformation.getDescriptorItemName());
    }

    // <descriptor item name>
    // ::= CARDINALITY
    //   | CHARACTER_SET_CATALOG
    //   | CHARACTER_SET_NAME
    //   | CHARACTER_SET_SCHEMA
    //   | COLLATION_CATALOG
    //   | COLLATION_NAME
    //   | COLLATION_SCHEMA
    //   | DATA
    //   | DATETIME_INTERVAL_CODE
    //   | DATETIME_INTERVAL_PRECISION
    //   | DEGREE
    //   | INDICATOR
    //   | KEY_MEMBER
    //   | LENGTH
    //   | LEVEL
    //   | NAME
    //   | NULLABLE
    //   | OCTET_LENGTH
    //   | PARAMETER_MODE
    //   | PARAMETER_ORDINAL_POSITION
    //   | PARAMETER_SPECIFIC_CATALOG
    //   | PARAMETER_SPECIFIC_NAME
    //   | PARAMETER_SPECIFIC_SCHEMA
    //   | PRECISION
    //   | RETURNED_CARDINALITY
    //   | RETURNED_LENGTH
    //   | RETURNED_OCTET_LENGTH
    //   | SCALE
    //   | SCOPE_CATALOG
    //   | SCOPE_NAME
    //   | SCOPE_SCHEMA
    //   | TYPE
    //   | UNNAMED
    //   | USER_DEFINED_TYPE_CATALOG
    //   | USER_DEFINED_TYPE_NAME
    //   | USER_DEFINED_TYPE_SCHEMA
    //   | USER_DEFINED_TYPE_CODE
    private void generate(DescriptorItemName descriptorItemName) {
        DescriptorItemNameType type = descriptorItemName.getDescriptorItemNameType();
        if (type == DescriptorItemNameType.CARDINALITY) {
            append("CARDINALITY");
            return;
        }
        if (type == DescriptorItemNameType.CHARACTER_SET_CATALOG) {
            append("CHARACTER_SET_CATALOG");
            return;
        }
        if (type == DescriptorItemNameType.CHARACTER_SET_NAME) {
            append("CHARACTER_SET_NAME");
            return;
        }
        if (type == DescriptorItemNameType.CHARACTER_SET_SCHEMA) {
            append("CHARACTER_SET_SCHEMA");
            return;
        }
        if (type == DescriptorItemNameType.COLLATION_CATALOG) {
            append("COLLATION_CATALOG");
            return;
        }
        if (type == DescriptorItemNameType.COLLATION_NAME) {
            append("COLLATION_NAME");
            return;
        }
        if (type == DescriptorItemNameType.COLLATION_SCHEMA) {
            append("COLLATION_SCHEMA");
            return;
        }
        if (type == DescriptorItemNameType.DATA) {
            append("DATA");
            return;
        }
        if (type == DescriptorItemNameType.DATETIME_INTERVAL_CODE) {
            append("DATETIME_INTERVAL_CODE");
            return;
        }
        if (type == DescriptorItemNameType.DATETIME_INTERVAL_PRECISION) {
            append("DATETIME_INTERVAL_PRECISION");
            return;
        }
        if (type == DescriptorItemNameType.DEGREE) {
            append("DEGREE");
            return;
        }
        if (type == DescriptorItemNameType.INDICATOR) {
            append(TokenType.INDICATOR.getContent());
            return;
        }
        if (type == DescriptorItemNameType.KEY_MEMBER) {
            append("KEY_MEMBER");
            return;
        }
        if (type == DescriptorItemNameType.LENGTH) {
            append("LENGTH");
            return;
        }
        if (type == DescriptorItemNameType.LEVEL) {
            append("LEVEL");
            return;
        }
        if (type == DescriptorItemNameType.NAME) {
            append("NAME");
            return;
        }
        if (type == DescriptorItemNameType.NULLABLE) {
            append("NULLABLE");
            return;
        }
        if (type == DescriptorItemNameType.OCTET_LENGTH) {
            append("OCTET_LENGTH");
            return;
        }
        if (type == DescriptorItemNameType.PARAMETER_MODE) {
            append("PARAMETER_MODE");
            return;
        }
        if (type == DescriptorItemNameType.PARAMETER_ORDINAL_POSITION) {
            append("PARAMETER_ORDINAL_POSITION");
            return;
        }
        if (type == DescriptorItemNameType.PARAMETER_SPECIFIC_CATALOG) {
            append("PARAMETER_SPECIFIC_CATALOG");
            return;
        }
        if (type == DescriptorItemNameType.PARAMETER_SPECIFIC_NAME) {
            append("PARAMETER_SPECIFIC_NAME");
            return;
        }
        if (type == DescriptorItemNameType.PARAMETER_SPECIFIC_SCHEMA) {
            append("PARAMETER_SPECIFIC_SCHEMA");
            return;
        }
        if (type == DescriptorItemNameType.PRECISION) {
            append(TokenType.PRECISION.getContent());
            return;
        }
        if (type == DescriptorItemNameType.RETURNED_CARDINALITY) {
            append("RETURNED_CARDINALITY");
            return;
        }
        if (type == DescriptorItemNameType.RETURNED_LENGTH) {
            append("RETURNED_LENGTH");
            return;
        }
        if (type == DescriptorItemNameType.RETURNED_OCTET_LENGTH) {
            append("RETURNED_OCTET_LENGTH");
            return;
        }
        if (type == DescriptorItemNameType.SCALE) {
            append("SCALE");
            return;
        }
        if (type == DescriptorItemNameType.SCOPE_CATALOG) {
            append("SCOPE_CATALOG");
            return;
        }
        if (type == DescriptorItemNameType.SCOPE_NAME) {
            append("SCOPE_NAME");
            return;
        }
        if (type == DescriptorItemNameType.SCOPE_SCHEMA) {
            append("SCOPE_SCHEMA");
            return;
        }
        if (type == DescriptorItemNameType.TYPE) {
            append("TYPE");
            return;
        }
        if (type == DescriptorItemNameType.UNNAMED) {
            append("UNNAMED");
            return;
        }
        if (type == DescriptorItemNameType.USER_DEFINED_TYPE_CATALOG) {
            append("USER_DEFINED_TYPE_CATALOG");
            return;
        }
        if (type == DescriptorItemNameType.USER_DEFINED_TYPE_NAME) {
            append("USER_DEFINED_TYPE_NAME");
            return;
        }
        if (type == DescriptorItemNameType.USER_DEFINED_TYPE_SCHEMA) {
            append("USER_DEFINED_TYPE_SCHEMA");
            return;
        }
        if (type == DescriptorItemNameType.USER_DEFINED_TYPE_CODE) {
            append("USER_DEFINED_TYPE_CODE");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), descriptorItemName.getBeginIndex(), "This descriptor item name is not supported.");
    }

    // <get diagnostics statement> ::= GET DIAGNOSTICS <SQL diagnostics information>
    private void generate(GetDiagnosticsStatement getDiagnosticsStatement) {
        append(TokenType.GET.getContent());
        append(' ');
        append("DIAGNOSTICS");
        append(' ');
        generate(getDiagnosticsStatement.getSqlDiagnosticsInformation());
    }

    // <SQL diagnostics information> ::= <statement information> | <condition information>
    private void generate(SqlDiagnosticsInformation sqlDiagnosticsInformation) {
        if (sqlDiagnosticsInformation instanceof StatementInformation) {
            generate((StatementInformation) sqlDiagnosticsInformation);
            return;
        }
        if (sqlDiagnosticsInformation instanceof ConditionInformation) {
            generate((ConditionInformation) sqlDiagnosticsInformation);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), sqlDiagnosticsInformation.getBeginIndex(), "This SQL diagnostics information is not supported, " + sqlDiagnosticsInformation.getClass().getName());
    }

    // <statement information> ::= <statement information item> [ { <comma> <statement information item> }... ]
    private void generate(StatementInformation statementInformation) {
        for (int i = 0; i < statementInformation.size(); i++) {
            generate(statementInformation.get(i));
            if (i < statementInformation.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <statement information item>
    // ::=
    // <simple target specification>
    // <equals operator>
    // <statement information item name>
    private void generate(StatementInformationItem statementInformationItem) {
        generate(statementInformationItem.getSimpleTargetSpecification());
        append(TokenType.EQUALS_OPERATOR.getContent());
        generate(statementInformationItem.getStatementInformationItemName());
    }

    // <statement information item name>
    // ::= NUMBER
    //   | MORE
    //   | COMMAND_FUNCTION
    //   | COMMAND_FUNCTION_CODE
    //   | DYNAMIC_FUNCTION
    //   | DYNAMIC_FUNCTION_CODE
    //   | ROW_COUNT
    //   | TRANSACTIONS_COMMITTED
    //   | TRANSACTIONS_ROLLED_BACK
    //   | TRANSACTION_ACTIVE
    private void generate(StatementInformationItemName statementInformationItemName) {
        if (statementInformationItemName.isNumber()) {
            append("NUMBER");
            return;
        }
        if (statementInformationItemName.isMore()) {
            append("MORE");
            return;
        }
        if (statementInformationItemName.isCommandFunction()) {
            append("COMMAND_FUNCTION");
            return;
        }
        if (statementInformationItemName.isCommandFunctionCode()) {
            append("COMMAND_FUNCTION_CODE");
            return;
        }
        if (statementInformationItemName.isDynamicFunction()) {
            append("DYNAMIC_FUNCTION");
            return;
        }
        if (statementInformationItemName.isDynamicFunctionCode()) {
            append("DYNAMIC_FUNCTION_CODE");
            return;
        }
        if (statementInformationItemName.isRowCount()) {
            append("ROW_COUNT");
            return;
        }
        if (statementInformationItemName.isTransactionsCommitted()) {
            append("TRANSACTIONS_COMMITTED");
            return;
        }
        if (statementInformationItemName.isTransactionsRolledBack()) {
            append("TRANSACTIONS_ROLLED_BACK");
            return;
        }
        if (statementInformationItemName.isTransactionActive()) {
            append("TRANSACTION_ACTIVE");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), statementInformationItemName.getBeginIndex(), "This statement information item name is not supported.");
    }

    // <condition information>
    // ::=
    // { EXCEPTION | CONDITION }
    // <condition number>
    // <condition information item> [ { <comma> <condition information item> }... ]
    private void generate(ConditionInformation conditionInformation) {
        if (conditionInformation.isException()) {
            append("EXCEPTION");
        } else if (conditionInformation.isCondition()) {
            append("EXCEPTION");
        } else {
            throw new YuliaException(getSql(), getLineNumber(), conditionInformation.getBeginIndex(), "This condition information is not supported.");
        }
        append(' ');
        generate(conditionInformation.getConditionNumber());
        append(' ');
        ConditionInformationItemList conditionInformationItemList
                = conditionInformation.getConditionInformationItemList();
        for (int i = 0; i < conditionInformationItemList.size(); i++) {
            generate(conditionInformationItemList.get(i));
            if (i < conditionInformationItemList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <condition information item>
    // ::=
    // <simple target specification>
    // <equals operator>
    // <condition information item name>
    private void generate(ConditionInformationItem conditionInformationItem) {
        generate(conditionInformationItem.getSimpleTargetSpecification());
        append(TokenType.EQUALS_OPERATOR.getContent());
        generate(conditionInformationItem.getConditionInformationItemName());
    }

    // <condition information item name>
    // ::= CATALOG_NAME
    //   | CLASS_ORIGIN
    //   | COLUMN_NAME
    //   | CONDITION_NUMBER
    //   | CONNECTION_NAME
    //   | CONSTRAINT_CATALOG
    //   | CONSTRAINT_NAME
    //   | CONSTRAINT_SCHEMA
    //   | CURSOR_NAME
    //   | MESSAGE_LENGTH
    //   | MESSAGE_OCTET_LENGTH
    //   | MESSAGE_TEXT
    //   | PARAMETER_MODE
    //   | PARAMETER_NAME
    //   | PARAMETER_ORDINAL_POSITION
    //   | RETURNED_SQLSTATE
    //   | ROUTINE_CATALOG
    //   | ROUTINE_NAME
    //   | ROUTINE_SCHEMA
    //   | SCHEMA_NAME
    //   | SERVER_NAME
    //   | SPECIFIC_NAME
    //   | SUBCLASS_ORIGIN
    //   | TABLE_NAME
    //   | TRIGGER_CATALOG
    //   | TRIGGER_NAME
    //   | TRIGGER_SCHEMA
    private void generate(ConditionInformationItemName conditionInformationItemName) {
        if (conditionInformationItemName.isCatalogName()) {
            append("CATALOG_NAME");
            return;
        }
        if (conditionInformationItemName.isClassOrigin()) {
            append("CLASS_ORIGIN");
            return;
        }
        if (conditionInformationItemName.isColumnName()) {
            append("COLUMN_NAME");
            return;
        }
        if (conditionInformationItemName.isConditionNumber()) {
            append("CONDITION_NUMBER");
            return;
        }
        if (conditionInformationItemName.isConnectionName()) {
            append("CONNECTION_NAME");
            return;
        }
        if (conditionInformationItemName.isConstraintCatalog()) {
            append("CONSTRAINT_CATALOG");
            return;
        }
        if (conditionInformationItemName.isConstraintName()) {
            append("CONSTRAINT_NAME");
            return;
        }
        if (conditionInformationItemName.isConstraintSchema()) {
            append("CONSTRAINT_SCHEMA");
            return;
        }
        if (conditionInformationItemName.isCursorName()) {
            append("CURSOR_NAME");
            return;
        }
        if (conditionInformationItemName.isMessageLength()) {
            append("MESSAGE_LENGTH");
            return;
        }
        if (conditionInformationItemName.isMessageOctetLength()) {
            append("MESSAGE_OCTET_LENGTH");
            return;
        }
        if (conditionInformationItemName.isMessageText()) {
            append("MESSAGE_TEXT");
            return;
        }
        if (conditionInformationItemName.isParameterMode()) {
            append("PARAMETER_MODE");
            return;
        }
        if (conditionInformationItemName.isParameterName()) {
            append("PARAMETER_NAME");
            return;
        }
        if (conditionInformationItemName.isParameterOrdinalPosition()) {
            append("PARAMETER_ORDINAL_POSITION");
            return;
        }
        if (conditionInformationItemName.isReturnedSqlstate()) {
            append("RETURNED_SQLSTATE");
            return;
        }
        if (conditionInformationItemName.isRoutineCatalog()) {
            append("ROUTINE_CATALOG");
            return;
        }
        if (conditionInformationItemName.isRoutineName()) {
            append("ROUTINE_NAME");
            return;
        }
        if (conditionInformationItemName.isRoutineSchema()) {
            append("ROUTINE_SCHEMA");
            return;
        }
        if (conditionInformationItemName.isSchemaName()) {
            append("SCHEMA_NAME");
            return;
        }
        if (conditionInformationItemName.isServerName()) {
            append("SERVER_NAME");
            return;
        }
        if (conditionInformationItemName.isSpecificName()) {
            append("SPECIFIC_NAME");
            return;
        }
        if (conditionInformationItemName.isSubclassOrigin()) {
            append("SUBCLASS_ORIGIN");
            return;
        }
        if (conditionInformationItemName.isTableName()) {
            append("TABLE_NAME");
            return;
        }
        if (conditionInformationItemName.isTriggerCatalog()) {
            append("TRIGGER_CATALOG");
            return;
        }
        if (conditionInformationItemName.isTriggerName()) {
            append("TRIGGER_NAME");
            return;
        }
        if (conditionInformationItemName.isTriggerSchema()) {
            append("TRIGGER_SCHEMA");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), conditionInformationItemName.getBeginIndex(), "This condition information item name is not supported.");
    }

    // <grant privilege statement>
    // ::=
    // GRANT <privileges>
    // TO <grantee> [ { <comma> <grantee> }... ]
    // [ WITH HIERARCHY OPTION ]
    // [ WITH GRANT OPTION ]
    // [ GRANTED BY <grantor> ]
    private void generate(GrantPrivilegeStatement grantPrivilegeStatement) {
        append(TokenType.GRANT.getContent());
        append(' ');
        generate(grantPrivilegeStatement.getPrivileges());
        append(' ');
        append(TokenType.TO.getContent());
        append(' ');
        generate(grantPrivilegeStatement.getGranteeList());
        if (grantPrivilegeStatement.isWithHierarchyOption()) {
            append(' ');
            append(TokenType.WITH.getContent());
            append(' ');
            append("HIERARCHY");
            append(' ');
            append("OPTION");
        }
        if (grantPrivilegeStatement.isWithGrantOption()) {
            append(' ');
            append(TokenType.WITH.getContent());
            append(' ');
            append(TokenType.GRANT.getContent());
            append(' ');
            append("OPTION");
        }
        Grantor grantor = grantPrivilegeStatement.getGrantor();
        if (grantor != null) {
            append(' ');
            append("GRANTED");
            append(' ');
            append(TokenType.BY.getContent());
            append(' ');
            generate(grantor);
        }
    }

    // <grant role statement>
    // ::=
    // GRANT <role granted> [ { <comma> <role granted> }... ]
    // TO <grantee> [ { <comma> <grantee> }... ]
    // [ WITH ADMIN OPTION ]
    // [ GRANTED BY <grantor> ]
    private void generate(GrantRoleStatement grantRoleStatement) {
        append(TokenType.GRANT.getContent());
        append(' ');
        generate(grantRoleStatement.getRoleGrantedList());
        append(' ');
        append(TokenType.TO.getContent());
        append(' ');
        generate(grantRoleStatement.getGranteeList());
        if (grantRoleStatement.isWithAdminOption()) {
            append(' ');
            append(TokenType.WITH.getContent());
            append(' ');
            append("ADMIN");
            append(' ');
            append("OPTION");
        }
        Grantor grantor = grantRoleStatement.getGrantor();
        if (grantor != null) {
            append(' ');
            append("GRANTED");
            append(' ');
            append(TokenType.BY.getContent());
            append(' ');
            generate(grantor);
        }
    }

    // <hold locator statement> ::= HOLD LOCATOR <locator reference> [ { <comma> <locator reference> }... ]
    private void generate(HoldLocatorStatement holdLocatorStatement) {
        append(TokenType.HOLD.getContent());
        append(' ');
        append("LOCATOR");
        append(' ');
        LocatorReferenceList locatorReferenceList
                = holdLocatorStatement.getLocatorReferenceList();
        for (int i = 0; i < locatorReferenceList.size(); i++) {
            generate(locatorReferenceList.get(i));
            if (i < locatorReferenceList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <insert statement> ::= INSERT INTO <insertion target> <insert columns and source>
    private void generate(InsertStatement insertStatement) {
        append(TokenType.INSERT.getContent());
        append(' ');
        append(TokenType.INTO.getContent());
        append(' ');
        generate(insertStatement.getInsertionTarget());
        append(' ');
        generate(insertStatement.getInsertColumnsAndSource());
    }

    // <insert columns and source>
    // ::= <from subquery>
    //   | <from constructor>
    //   | <from default>
    private void generate(InsertColumnsAndSource insertColumnsAndSource) {
        if (insertColumnsAndSource instanceof FromSubquery) {
            generate((FromSubquery) insertColumnsAndSource);
            return;
        }
        if (insertColumnsAndSource instanceof FromConstructor) {
            generate((FromConstructor) insertColumnsAndSource);
            return;
        }
        if (insertColumnsAndSource instanceof FromDefault) {
            generate((FromDefault) insertColumnsAndSource);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), insertColumnsAndSource.getBeginIndex(), "This insert columns and source is not supported, " + insertColumnsAndSource.getClass().getName());
    }

    // <from subquery>
    // ::=
    // [ <left paren> <insert column list> <right paren> ]
    // [ <override clause> ]
    // <query expression>
    private void generate(FromSubquery fromSubquery) {
        IdentifierList insertColumnList = fromSubquery.getInsertColumnList();
        if (insertColumnList != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(insertColumnList);
            append(TokenType.RIGHT_PAREN.getContent());
            append(' ');
        }
        OverrideClause overrideClause = fromSubquery.getOverrideClause();
        if (overrideClause != null) {
            generate(overrideClause);
            append(' ');
        }
        generate(fromSubquery.getQueryExpression());
    }

    // <override clause> ::= OVERRIDING USER VALUE | OVERRIDING SYSTEM VALUE
    private void generate(OverrideClause overrideClause) {
        append("OVERRIDING");
        append(' ');
        if (overrideClause.isOverridingUserValue()) {
            append(TokenType.USER.getContent());
        } else if (overrideClause.isOverridingSystemValue()) {
            append(TokenType.SYSTEM.getContent());
        } else {
            throw new YuliaException(getSql(), getLineNumber(), overrideClause.getBeginIndex(), "This override clause is not supported.");
        }
        append(' ');
        append(TokenType.VALUE.getContent());
    }

    // <from constructor>
    // ::=
    // [ <left paren> <insert column list> <right paren> ]
    // [ <override clause> ]
    // <contextually typed table value constructor>
    private void generate(FromConstructor fromConstructor) {
        IdentifierList insertColumnList = fromConstructor.getInsertColumnList();
        if (insertColumnList != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(insertColumnList);
            append(TokenType.RIGHT_PAREN.getContent());
            append(' ');
        }
        OverrideClause overrideClause = fromConstructor.getOverrideClause();
        if (overrideClause != null) {
            generate(overrideClause);
            append(' ');
        }
        generate(fromConstructor.getContextuallyTypedRowValueExpressionList());
    }

    // <contextually typed table value constructor> ::= VALUES <contextually typed row value expression list>
    private void generate(ContextuallyTypedRowValueExpressionList contextuallyTypedRowValueExpressionList) {
        append(TokenType.VALUES.getContent());
        append(' ');
        for (int i = 0; i < contextuallyTypedRowValueExpressionList.size(); i++) {
            generate(contextuallyTypedRowValueExpressionList.get(i));
            if (i < contextuallyTypedRowValueExpressionList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <from default> ::= DEFAULT VALUES
    private void generate(FromDefault fromDefault) {
        append(TokenType.DEFAULT.getContent());
        append(' ');
        append(TokenType.VALUES.getContent());
    }

    // <merge statement>
    // ::=
    // MERGE INTO <target table>
    // [ [ AS ] <merge correlation name> ]
    // USING <table reference>
    // ON <search condition>
    // <merge operation specification>
    private void generate(MergeStatement mergeStatement) {
        append(TokenType.MERGE.getContent());
        append(' ');
        append(TokenType.INTO.getContent());
        append(' ');
        generate(mergeStatement.getTargetTable());
        append(' ');
        Identifier mergeCorrelationName = mergeStatement.getMergeCorrelationName();
        if (mergeCorrelationName != null) {
            generate(mergeCorrelationName);
            append(' ');
        }
        append(TokenType.USING.getContent());
        append(' ');
        generate(mergeStatement.getTableReference());
        append(' ');
        append(TokenType.ON.getContent());
        append(' ');
        generate(mergeStatement.getSearchCondition());
        append(' ');
        generate(mergeStatement.getMergeOperationSpecification());
    }

    // <merge when clause>
    // ::= <merge when matched clause>
    //   | <merge when not matched clause>
    private void generate(MergeWhenClause mergeWhenClause) {
        if (mergeWhenClause instanceof MergeWhenMatchedClause) {
            generate((MergeWhenMatchedClause) mergeWhenClause);
            return;
        }
        if (mergeWhenClause instanceof MergeWhenNotMatchedClause) {
            generate((MergeWhenNotMatchedClause) mergeWhenClause);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), mergeWhenClause.getBeginIndex(), "This merge when clause is not supported, " + mergeWhenClause.getClass().getName());
    }

    // <merge when matched clause> ::= WHEN MATCHED THEN <merge update specification>
    private void generate(MergeWhenMatchedClause mergeWhenMatchedClause) {
        append(TokenType.WHEN.getContent());
        append(' ');
        append("MATCHED");
        append(' ');
        append(TokenType.THEN.getContent());
        append(' ');
        generate(mergeWhenMatchedClause.getMergeUpdateSpecification());
    }

    // <merge update specification> ::= UPDATE SET <set clause list>
    private void generate(MergeUpdateSpecification mergeUpdateSpecification) {
        append(TokenType.UPDATE.getContent());
        append(' ');
        append(TokenType.SET.getContent());
        append(' ');
        generate(mergeUpdateSpecification.getSetClauseList());
    }

    // <merge when not matched clause> ::= WHEN NOT MATCHED THEN <merge insert specification>
    private void generate(MergeWhenNotMatchedClause mergeWhenNotMatchedClause) {
        append(TokenType.WHEN.getContent());
        append(' ');
        append(TokenType.NOT.getContent());
        append(' ');
        append("MATCHED");
        append(' ');
        append(TokenType.THEN.getContent());
        append(' ');
        generate(mergeWhenNotMatchedClause.getMergeInsertSpecification());
    }

    // <merge insert specification>
    // ::=
    // INSERT
    // [ <left paren> <insert column list> <right paren> ]
    // [ <override clause> ]
    // VALUES
    // <merge insert value list>
    private void generate(MergeInsertSpecification mergeInsertSpecification) {
        append(TokenType.INSERT.getContent());
        append(' ');
        IdentifierList insertColumnList = mergeInsertSpecification.getInsertColumnList();
        if (insertColumnList != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(insertColumnList);
            append(TokenType.RIGHT_PAREN.getContent());
            append(' ');
        }
        OverrideClause overrideClause = mergeInsertSpecification.getOverrideClause();
        if (overrideClause != null) {
            generate(overrideClause);
            append(' ');
        }
        append(TokenType.VALUES.getContent());
        append(' ');
        append(TokenType.LEFT_PAREN.getContent());
        for (int i = 0; i < mergeInsertSpecification.mergeInsertValueListSize(); i++) {
            generate(mergeInsertSpecification.getMergeInsertValue(i));
            if (i < mergeInsertSpecification.mergeInsertValueListSize() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <merge insert value element> ::= <value expression> | <contextually typed value specification>
    private void generate(MergeInsertValueElement mergeInsertValueElement) {
        if (mergeInsertValueElement instanceof ValueExpression) {
            generate((ValueExpression) mergeInsertValueElement);
            return;
        }
        if (mergeInsertValueElement instanceof ContextuallyTypedValueSpecification) {
            generate((ContextuallyTypedValueSpecification) mergeInsertValueElement);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), mergeInsertValueElement.getBeginIndex(), "This merge insert value element is not supported, " + mergeInsertValueElement.getClass().getName());
    }

    // <open statement> ::= OPEN <cursor name>
    private void generate(OpenStatement openStatement) {
        append(TokenType.OPEN.getContent());
        append(' ');
        generate(openStatement.getCursorName());
    }

    // <prepare statement>
    // ::=
    // PREPARE
    // <SQL statement name>
    // [ <attributes specification> ]
    // FROM
    // <SQL statement variable>
    private void generate(PrepareStatement prepareStatement) {
        append(TokenType.PREPARE.getContent());
        append(' ');
        generate(prepareStatement.getSqlStatementName());
        append(' ');
        SimpleValueSpecification attributesVariable
                = prepareStatement.getAttributesVariable();
        if (attributesVariable != null) {
            append("ATTRIBUTES");
            append(' ');
            generate(attributesVariable);
            append(' ');
        }
        append(TokenType.FROM.getContent());
        append(' ');
        generate(prepareStatement.getSqlStatementVariable());
    }

    // <query specification> ::= SELECT [ <set quantifier> ] <select list> <table expression>
    private void generate(QuerySpecification querySpecification) {
        append(TokenType.SELECT.getContent());
        SetQuantifier setQuantifier = querySpecification.getSetQuantifier();
        if (setQuantifier != null) {
            append(' ');
            generate(querySpecification.getSetQuantifier());
        }
        append(' ');
        generate(querySpecification.getSelectList());
        append(' ');
        generate(querySpecification.getTableExpression());
    }

    // <set quantifier> ::= DISTINCT | ALL
    private void generate(SetQuantifier setQuantifier) {
        if (setQuantifier.isDistinct()) {
            append(TokenType.DISTINCT.getContent());
            return;
        }
        if (setQuantifier.isAll()) {
            append(TokenType.ALL.getContent());
            return;
        }
    }

    // <select list> ::= <asterisk> | <select sublist> [ { <comma> <select sublist> }... ]
    private void generate(SelectList selectList) {
        if (selectList.isAsterisk()) {
            append(TokenType.ASTERISK.getContent());
            return;
        }
        for (int i = 0; i < selectList.size(); i++) {
            generate(selectList.get(i));
            if (i < selectList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <select sublist> ::= <derived column> | <qualified asterisk>
    private void generate(SelectSublist selectSublist) {
        if (selectSublist instanceof DerivedColumn) {
            generate((DerivedColumn) selectSublist);
            return;
        }
        if (selectSublist instanceof QualifiedAsterisk) {
            generate((QualifiedAsterisk) selectSublist);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), selectSublist.getBeginIndex(), "This select sublist is not supported, " + selectSublist.getClass().getName());
    }

    // <derived column> ::= <value expression> [ <as clause> ]
    private void generate(DerivedColumn derivedColumn) {
        generate(derivedColumn.getValueExpression());
        AsClause asClause = derivedColumn.getAsClause();
        if (asClause != null) {
            generate(derivedColumn.getAsClause());
        }
    }

    // <value expression>
    // ::= <common value expression>
    //   | <boolean value expression>
    //   | <row value expression>
    private void generate(ValueExpression valueExpression) {
        if (valueExpression instanceof CommonValueExpression) {
            CommonValueExpression commonValueExpression = (CommonValueExpression) valueExpression;
            generate(commonValueExpression);
            return;
        }
        if (valueExpression instanceof BooleanValueExpression) {
            BooleanValueExpression booleanValueExpression = (BooleanValueExpression) valueExpression;
            generate(booleanValueExpression);
            return;
        }
        if (valueExpression instanceof RowValueExpression) {
            RowValueExpression rowValueExpression = (RowValueExpression) valueExpression;
            generate(rowValueExpression);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), valueExpression.getBeginIndex(), "This value expression is not supported, " + valueExpression.getClass().getName());
    }

    // <common value expression>
    // ::=
    //   <numeric value expression>
    // | <string value expression>
    // | <datetime value expression>
    // | <interval value expression>
    // | <user-defined type value expression>
    // | <reference value expression>
    // | <collection value expression>
    private void generate(CommonValueExpression commonValueExpression) {
        if (commonValueExpression instanceof NumericValueExpression) {
            generate((NumericValueExpression) commonValueExpression);
            return;
        }
        if (commonValueExpression instanceof StringValueExpression) {
            generate((StringValueExpression) commonValueExpression);
            return;
        }
        if (commonValueExpression instanceof DatetimeValueExpression) {
            generate((DatetimeValueExpression) commonValueExpression);
            return;
        }
        if (commonValueExpression instanceof IntervalValueExpression) {
            generate((IntervalValueExpression) commonValueExpression);
            return;
        }
        if (commonValueExpression instanceof ValueExpressionPrimary) {
            generate((ValueExpressionPrimary) commonValueExpression);
            return;
        }
        if (commonValueExpression instanceof CollectionValueExpression) {
            generate((CollectionValueExpression) commonValueExpression);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), commonValueExpression.getBeginIndex(), "This common value expression is not supported, " + commonValueExpression.getClass().getName());
    }

    // <string value expression> ::= <character value expression> | <blob value expression>
    private void generate(StringValueExpression stringValueExpression) {
        if (stringValueExpression instanceof StringFactor) {
            generate((StringFactor) stringValueExpression);
            return;
        }
        if (stringValueExpression instanceof StringConcatenation) {
            generate((StringConcatenation) stringValueExpression);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), stringValueExpression.getBeginIndex(), "This string value expression is not supported, " + stringValueExpression.getClass().getName());
    }

    private void generate(StringFactor stringFactor) {
        generate(stringFactor.getStringPrimary());
        CollateClause collateClause = stringFactor.getCollateClause();
        if (collateClause != null) {
            append(' ');
            generate(collateClause);
        }
    }

    private void generate(StringPrimary stringPrimary) {
        if (stringPrimary instanceof ValueExpressionPrimary) {
            generate((ValueExpressionPrimary) stringPrimary);
            return;
        }
        if (stringPrimary instanceof StringValueFunction) {
            generate((StringValueFunction) stringPrimary);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), stringPrimary.getBeginIndex(), "This string primary is not supported, " + stringPrimary.getClass().getName());
    }

    private void generate(StringValueFunction stringValueFunction) {
        if (stringValueFunction instanceof SpecificTypeMethod) {
            throw new RuntimeException("TODO");
        }
        if (stringValueFunction instanceof CharacterTransliteration) {
            throw new RuntimeException("TODO");
        }
        if (stringValueFunction instanceof Fold) {
            throw new RuntimeException("TODO");
        }
        if (stringValueFunction instanceof NormalizeFunction) {
            throw new RuntimeException("TODO");
        }
        if (stringValueFunction instanceof OverlayFunction) {
            throw new RuntimeException("TODO");
        }
        if (stringValueFunction instanceof RegularExpressionSubstringFunction) {
            throw new RuntimeException("TODO");
        }
        if (stringValueFunction instanceof SubstringFunction) {
            throw new RuntimeException("TODO");
        }
        if (stringValueFunction instanceof Transcoding) {
            throw new RuntimeException("TODO");
        }
        if (stringValueFunction instanceof TrimFunction) {
            throw new RuntimeException("TODO");
        }
        throw new YuliaException(getSql(), getLineNumber(), stringValueFunction.getBeginIndex(), "This string value function is not supported, " + stringValueFunction.getClass().getName());
    }

    private void generate(StringConcatenation stringConcatenation) {
        generate(stringConcatenation.getStringValueExpression());
        append(TokenType.CONCATENATION_OPERATOR.getContent());
        generate(stringConcatenation.getCharacterOrBlobFactor());
    }

    // <datetime value expression>
    // ::= <datetime term>
    //   | <interval value expression> <plus sign> <datetime term>
    //   | <datetime value expression> <plus sign> <interval term>
    //   | <datetime value expression> <minus sign> <interval term>
    private void generate(DatetimeValueExpression datetimeValueExpression) {
        if (datetimeValueExpression instanceof DatetimeTerm) {
            throw new RuntimeException("TODO");
        }
        if (datetimeValueExpression instanceof IntervalValueExpressionPlusDatetimeTerm) {
            throw new RuntimeException("TODO");
        }
        if (datetimeValueExpression instanceof DatetimeValueExpressionPlusIntervalTerm) {
            throw new RuntimeException("TODO");
        }
        if (datetimeValueExpression instanceof DatetimeValueExpressionMinusIntervalTerm) {
            throw new RuntimeException("TODO");
        }
        throw new YuliaException(getSql(), getLineNumber(), datetimeValueExpression.getBeginIndex(), "This datetime value expression is not supported, " + datetimeValueExpression.getClass().getName());
    }

    // <interval value expression>
    // ::= <interval term>
    //   | <interval value expression 1> <plus sign> <interval term 1>
    //   | <interval value expression 1> <minus sign> <interval term 1>
    //   | <left paren> <datetime value expression> <minus sign> <datetime term> <right paren> <interval qualifier>
    private void generate(IntervalValueExpression intervalValueExpression) {
        if (intervalValueExpression instanceof IntervalTerm) {
            throw new RuntimeException("TODO");
        }
        if (intervalValueExpression instanceof IntervalValueExpressionPlusIntervalTerm) {
            throw new RuntimeException("TODO");
        }
        if (intervalValueExpression instanceof IntervalValueExpressionMinusIntervalTerm) {
            throw new RuntimeException("TODO");
        }
        if (intervalValueExpression instanceof IntervalValueExpressionSubtype) {
            throw new RuntimeException("TODO");
        }
        throw new YuliaException(getSql(), getLineNumber(), intervalValueExpression.getBeginIndex(), "This interval value expression is not supported, " + intervalValueExpression.getClass().getName());
    }

    // <collection value expression> ::= <array value expression> | <multiset value expression>
    private void generate(CollectionValueExpression collectionValueExpression) {
        if (collectionValueExpression instanceof ArrayValueExpression) {
            generate((ArrayValueExpression) collectionValueExpression);
            return;
        }
        if (collectionValueExpression instanceof MultisetValueExpression) {
            generate((MultisetValueExpression) collectionValueExpression);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), collectionValueExpression.getBeginIndex(), "This collection value expression is not supported, " + collectionValueExpression.getClass().getName());
    }

    // <array value expression> ::= <array concatenation> | <array factor>
    private void generate(ArrayValueExpression arrayValueExpression) {
        for (int i = 0; i < arrayValueExpression.size(); i++) {
            generate(arrayValueExpression.get(i));
            if (i < arrayValueExpression.size() - 1) {
                append(TokenType.CONCATENATION_OPERATOR.getContent());
                append(' ');
            }
        }
    }

    // <multiset value expression>
    // ::= <multiset term>
    //   | <multiset value expression> MULTISET UNION [ ALL | DISTINCT ] <multiset term>
    //   | <multiset value expression> MULTISET EXCEPT [ ALL | DISTINCT ] <multiset term>
    private void generate(MultisetValueExpression multisetValueExpression) {
        if (multisetValueExpression instanceof MultisetTerm) {
            throw new RuntimeException("TODO");
        }
        if (multisetValueExpression instanceof MultisetUnion) {
            throw new RuntimeException("TODO");
        }
        if (multisetValueExpression instanceof MultisetExcept) {
            throw new RuntimeException("TODO");
        }
        throw new YuliaException(getSql(), getLineNumber(), multisetValueExpression.getBeginIndex(), "This multiset value expression is not supported, " + multisetValueExpression.getClass().getName());
    }

    // <boolean value expression>
    // ::= <boolean term>
    //   | <boolean value expression> OR <boolean term>
    private void generate(BooleanValueExpression booleanValueExpression) {
        for (int i = 0; i < booleanValueExpression.size(); i++) {
            generate(booleanValueExpression.get(i));
            if (i < booleanValueExpression.size() - 1) {
                append(' ').append(TokenType.OR.getContent()).append(' ');
            }
        }
    }

    // <boolean term>
    // ::= <boolean factor>
    //   | <boolean term> AND <boolean factor>
    private void generate(BooleanTerm booleanTerm) {
        for (int i = 0; i < booleanTerm.size(); i++) {
            generate(booleanTerm.get(i));
            if (i < booleanTerm.size() - 1) {
                append(' ').append(TokenType.AND.getContent()).append(' ');
            }
        }
    }

    // <boolean factor> ::= [ NOT ] <boolean test>
    private void generate(BooleanFactor booleanFactor) {
        if (booleanFactor.isNot()) {
            append(TokenType.NOT.getContent()).append(' ');
        }
        generate(booleanFactor.getBooleanTest());
    }

    // <boolean test> ::= <boolean primary> [ IS [ NOT ] <truth value> ]
    private void generate(BooleanTest booleanTest) {
        generate(booleanTest.getBooleanPrimary());
        if (booleanTest.isNot() || booleanTest.getTruthValue() != null) {
            append(TokenType.IS.getContent()).append(' ');
            if (booleanTest.isNot()) {
                append(TokenType.NOT.getContent()).append(' ');
            }
            generate(booleanTest.getTruthValue());
        }
    }

    // <boolean primary> ::= <predicate> | <boolean predicand>
    private void generate(BooleanPrimary booleanPrimary) {
        if (booleanPrimary instanceof Predicate) {
            generate((Predicate) booleanPrimary);
            return;
        }
        if (booleanPrimary instanceof BooleanPredicand) {
            generate((BooleanPredicand) booleanPrimary);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), booleanPrimary.getBeginIndex(), "This boolean primary is not supported, " + booleanPrimary.getClass().getName());
    }

    // <predicate>
    // ::=
    //   <comparison predicate>
    // | <between predicate>
    // | <in predicate>
    // | <like predicate>
    // | <similar predicate>
    // | <null predicate>
    // | <quantified comparison predicate>
    // | <exists predicate>
    // | <unique predicate>
    // | <normalized predicate>
    // | <match predicate>
    // | <overlaps predicate>
    // | <distinct predicate>
    // | <member predicate>
    // | <submultiset predicate>
    // | <set predicate>
    // | <type predicate>
    private void generate(Predicate predicate) {
        if (predicate instanceof ComparisonPredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof BetweenPredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof InPredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof LikePredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof SimilarPredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof NullPredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof QuantifiedComparisonPredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof ExistsPredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof UniquePredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof NormalizedPredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof MatchPredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof OverlapsPredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof DistinctPredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof MemberPredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof SubmultisetPredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof SetPredicate) {
            throw new RuntimeException("TODO");
        }
        if (predicate instanceof TypePredicate) {
            throw new RuntimeException("TODO");
        }
        throw new YuliaException(getSql(), getLineNumber(), predicate.getBeginIndex(), "This predicate is not supported, " + predicate.getClass().getName());
    }

    // <boolean predicand>
    // ::= <parenthesized boolean value expression>
    //   | <nonparenthesized value expression primary>
    private void generate(BooleanPredicand booleanPredicand) {
        if (booleanPredicand instanceof ParenthesizedBooleanValueExpression) {
            generate((ParenthesizedBooleanValueExpression) booleanPredicand);
            return;
        }
        if (booleanPredicand instanceof NonparenthesizedValueExpressionPrimary) {
            generate((NonparenthesizedValueExpressionPrimary) booleanPredicand);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), booleanPredicand.getBeginIndex(), "This boolean predicand is not supported, " + booleanPredicand.getClass().getName());
    }

    // <parenthesized boolean value expression> ::= <left paren> <boolean value expression> <right paren>
    private void generate(ParenthesizedBooleanValueExpression parenthesizedBooleanValueExpression) {
        append(TokenType.LEFT_PAREN.getContent());
        generate(parenthesizedBooleanValueExpression.getBooleanValueExpression());
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <truth value> ::= TRUE | FALSE | UNKNOWN
    private void generate(TruthValue truthValue) {
        if (truthValue.isTrue()) {
            append(TokenType.TRUE.getContent());
            return;
        }
        if (truthValue.isFalse()) {
            append(TokenType.FALSE.getContent());
            return;
        }
        if (truthValue.isUnknown()) {
            append(TokenType.UNKNOWN.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), truthValue.getBeginIndex(), "This truth value is not supported, " + truthValue.getClass().getName());
    }

    // <row value expression>
    // ::= <row value special case>
    //   | <explicit row value constructor>
    private void generate(RowValueExpression rowValueExpression) {
        if (rowValueExpression instanceof NonparenthesizedValueExpressionPrimary) {
            generate((NonparenthesizedValueExpressionPrimary) rowValueExpression);
            return;
        }
        if (rowValueExpression instanceof ExplicitRowValueConstructor) {
            generate((ExplicitRowValueConstructor) rowValueExpression);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), rowValueExpression.getBeginIndex(), "This row value expression is not supported, " + rowValueExpression.getClass().getName());
    }

    // <explicit row value constructor>
    // ::=
    //   <left paren> <row value constructor element> <comma> <row value constructor element list> <right paren>
    // | ROW <left paren> <row value constructor element list> <right paren>
    // | <row subquery>
    private void generate(ExplicitRowValueConstructor explicitRowValueConstructor) {
        ValueExpression rowValueConstructorElement = explicitRowValueConstructor.getRowValueConstructorElement();
        if (rowValueConstructorElement != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(rowValueConstructorElement);
            append(TokenType.COMMA.getContent());
            append(' ');
            generate(explicitRowValueConstructor.getRowValueConstructorElementList());
            append(TokenType.RIGHT_PAREN.getContent());
            return;
        }
        ValueExpressionList rowValueConstructorElementList = explicitRowValueConstructor.getRowValueConstructorElementList();
        if (rowValueConstructorElementList != null) {
            append(TokenType.ROW.getContent());
            append(TokenType.LEFT_PAREN.getContent());
            generate(rowValueConstructorElementList);
            append(TokenType.RIGHT_PAREN.getContent());
            return;
        }
        Subquery rowSubquery = explicitRowValueConstructor.getRowSubquery();
        generate(rowSubquery);
    }

    // <subquery> ::= <left paren> <query expression> <right paren>
    private void generate(Subquery subquery) {
        append(TokenType.LEFT_PAREN.getContent());
        generate(subquery.getQueryExpression());
        append(TokenType.RIGHT_PAREN.getContent());
    }

    private void generate(ValueExpressionList valueExpressionList) {
        for (int i = 0; i < valueExpressionList.size(); i++) {
            generate(valueExpressionList.get(i));
            if (i < valueExpressionList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <as clause> ::= [ AS ] <column name>
    private void generate(AsClause asClause) {
        append(TokenType.AS.getContent());
        append(' ');
        generate(asClause.getColumnName());
    }

    private void generate(Identifier identifier) {
        append(identifier.getContent());
    }

    // <qualified asterisk>
    // ::= <asterisked identifier chain> <period> <asterisk>
    //   | <all fields reference>
    private void generate(QualifiedAsterisk qualifiedAsterisk) {
        IdentifierChain asteriskedIdentifierChain = qualifiedAsterisk.getAsteriskedIdentifierChain();
        if (asteriskedIdentifierChain != null) {
            generate(asteriskedIdentifierChain);
            append(TokenType.PERIOD.getContent());
            append(TokenType.ASTERISK.getContent());
            return;
        }
        ValueExpressionPrimary valueExpressionPrimary = qualifiedAsterisk.getValueExpressionPrimary();
        generate(valueExpressionPrimary);
        append(TokenType.PERIOD.getContent());
        append(TokenType.ASTERISK.getContent());
        IdentifierList allFieldsColumnNameList = qualifiedAsterisk.getAllFieldsColumnNameList();
        if (allFieldsColumnNameList != null) {
            append(' ');
            append(TokenType.AS.getContent());
            append(' ');
            append(TokenType.LEFT_PAREN.getContent());
            generate(allFieldsColumnNameList);
            append(TokenType.RIGHT_PAREN.getContent());
        }
    }

    // <identifier> [ { <period> <identifier> }... ]
    private void generate(IdentifierChain identifierChain) {
        for (int i = 0; i < identifierChain.size(); i++) {
            generate(identifierChain.get(i));
            if (i < identifierChain.size() - 1) {
                append(TokenType.PERIOD.getContent());
            }
        }
    }

    // <value expression primary>
    // ::= <parenthesized value expression>
    //   | <nonparenthesized value expression primary>
    private void generate(ValueExpressionPrimary valueExpressionPrimary) {
        if (valueExpressionPrimary instanceof ParenthesizedValueExpression) {
            ParenthesizedValueExpression parenthesizedValueExpression = (ParenthesizedValueExpression) valueExpressionPrimary;
            generate(parenthesizedValueExpression);
            return;
        }
        if (valueExpressionPrimary instanceof NonparenthesizedValueExpressionPrimary) {
            NonparenthesizedValueExpressionPrimary nonparenthesizedValueExpressionPrimary = (NonparenthesizedValueExpressionPrimary) valueExpressionPrimary;
            generate(nonparenthesizedValueExpressionPrimary);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), valueExpressionPrimary.getBeginIndex(), "This value expression primary is not supported, " + valueExpressionPrimary.getClass().getName());
    }

    // <parenthesized value expression> ::= <left paren> <value expression> <right paren>
    private void generate(ParenthesizedValueExpression parenthesizedValueExpression) {
        append(TokenType.LEFT_PAREN.getContent());
        generate(parenthesizedValueExpression.getValueExpression());
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <nonparenthesized value expression primary>
    // ::=
    //   <unsigned value specification>
    // | <column reference>
    // | <set function specification>
    // | <window function>
    // | <scalar subquery>
    // | <case expression>
    // | <cast specification>
    // | <field reference>
    // | <subtype treatment>
    // | <method invocation>
    // | <static method invocation>
    // | <new specification>
    // | <attribute or method reference>
    // | <reference resolution>
    // | <collection value constructor>
    // | <array element reference>
    // | <multiset element reference>
    // | <routine invocation>
    // | <next value expression>
    private void generate(NonparenthesizedValueExpressionPrimary nonparenthesizedValueExpressionPrimary) {
        if (nonparenthesizedValueExpressionPrimary instanceof UnsignedValueSpecification) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof ColumnReference) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof SetFunctionSpecification) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof WindowFunction) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof Subquery) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof CaseExpression) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof CastSpecification) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof FieldReference) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof SubtypeTreatment) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof MethodInvocation) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof StaticMethodInvocation) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof NewSpecification) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof AttributeOrMethodReference) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof ReferenceResolution) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof CollectionValueConstructor) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof ArrayElementReference) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof MultisetElementReference) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof RoutineInvocation) {
            throw new RuntimeException("TODO");
        }
        if (nonparenthesizedValueExpressionPrimary instanceof NextValueExpression) {
            throw new RuntimeException("TODO");
        }
        throw new YuliaException(getSql(), getLineNumber(), nonparenthesizedValueExpressionPrimary.getBeginIndex(), "This nonparenthesized value expression primary is not supported, " + nonparenthesizedValueExpressionPrimary.getClass().getName());
    }

    // <identifier> [ { <comma> <identifier> }... ]
    private void generate(IdentifierList identifierList) {
        for (int i = 0; i < identifierList.size(); i++) {
            generate(identifierList.get(i));
            if (i < identifierList.size() - 1) {
                append(TokenType.COMMA.getContent());
            }
        }
    }

    // <table expression>
    // ::=
    // <from clause>
    // [ <where clause> ]
    // [ <group by clause> ]
    // [ <having clause> ]
    // [ <window clause> ]
    private void generate(TableExpression tableExpression) {
        FromClause fromClause = tableExpression.getFromClause();
        generate(fromClause);
        WhereClause whereClause = tableExpression.getWhereClause();
        if (whereClause != null) {
            append(' ');
            generate(whereClause);
        }
        GroupByClause groupByClause = tableExpression.getGroupByClause();
        if (groupByClause != null) {
            append(' ');
            generate(groupByClause);
        }
        HavingClause havingClause = tableExpression.getHavingClause();
        if (havingClause != null) {
            append(' ');
            generate(havingClause);
        }
        WindowClause windowClause = tableExpression.getWindowClause();
        if (whereClause != null) {
            append(' ');
            generate(windowClause);
        }
    }

    // <where clause> ::= WHERE <search condition>
    private void generate(WhereClause whereClause) {
        append(TokenType.WHERE.getContent());
        append(' ');
        generate(whereClause.getSearchCondition());
    }

    // <group by clause> ::= GROUP BY [ <set quantifier> ] <grouping element list>
    private void generate(GroupByClause groupByClause) {
        append(TokenType.GROUP.getContent());
        append(' ');
        append(TokenType.BY.getContent());
        append(' ');
        SetQuantifier setQuantifier = groupByClause.getSetQuantifier();
        if (setQuantifier != null) {
            generate(setQuantifier);
            append(' ');
        }
        generate(groupByClause.getGroupingElementList());
    }

    // <grouping element list> ::= <grouping element> [ { <comma> <grouping element> }... ]
    private void generate(GroupingElementList groupingElementList) {
        for (int i = 0; i < groupingElementList.size(); i++) {
            generate(groupingElementList.get(i));
            if (i < groupingElementList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <grouping element>
    // ::= <ordinary grouping set>
    //   | <rollup list>
    //   | <cube list>
    //   | <grouping sets specification>
    //   | <empty grouping set>
    private void generate(GroupingElement groupingElement) {
        if (groupingElement instanceof OrdinaryGroupingSet) {
            generate((OrdinaryGroupingSet) groupingElement);
            return;
        }
        if (groupingElement instanceof RollupList) {
            generate((RollupList) groupingElement);
            return;
        }
        if (groupingElement instanceof CubeList) {
            generate((CubeList) groupingElement);
            return;
        }
        if (groupingElement instanceof GroupingSetsSpecification) {
            generate((GroupingSetsSpecification) groupingElement);
            return;
        }
        if (groupingElement instanceof EmptyGroupingSet) {
            generate((EmptyGroupingSet) groupingElement);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), groupingElement.getBeginIndex(), "This grouping element is not supported, " + groupingElement.getClass().getName());
    }

    // <ordinary grouping set>
    // ::= <grouping column reference>
    //   | <left paren> <grouping column reference list> <right paren>
    private void generate(OrdinaryGroupingSet ordinaryGroupingSet) {
        if (ordinaryGroupingSet instanceof GroupingColumnReference) {
            generate((GroupingColumnReference) ordinaryGroupingSet);
            return;
        }
        if (ordinaryGroupingSet instanceof ParenthesizedGroupingColumnReferenceList) {
            generate((ParenthesizedGroupingColumnReferenceList) ordinaryGroupingSet);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), ordinaryGroupingSet.getBeginIndex(), "This ordinary grouping set is not supported, " + ordinaryGroupingSet.getClass().getName());
    }

    // <grouping column reference> ::= <column reference> [ <collate clause> ]
    private void generate(GroupingColumnReference groupingColumnReference) {
        generate(groupingColumnReference.getColumnReference());
        CollateClause collateClause = groupingColumnReference.getCollateClause();
        if (collateClause != null) {
            append(' ');
            generate(collateClause);
        }
    }

    // <left paren> <grouping column reference list> <right paren>
    private void generate(ParenthesizedGroupingColumnReferenceList parenthesizedGroupingColumnReferenceList) {
        append(TokenType.LEFT_PAREN.getContent());
        for (int i = 0; i < parenthesizedGroupingColumnReferenceList.size(); i++) {
            generate(parenthesizedGroupingColumnReferenceList.get(i));
            if (i < parenthesizedGroupingColumnReferenceList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <rollup list> ::= ROLLUP <left paren> <ordinary grouping set list> <right paren>
    private void generate(RollupList rollupList) {
        append(TokenType.ROLLUP.getContent());
        append(TokenType.LEFT_PAREN.getContent());
        generate(rollupList.getOrdinaryGroupingSetList());
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <ordinary grouping set list> ::= <ordinary grouping set> [ { <comma> <ordinary grouping set> }... ]
    private void generate(OrdinaryGroupingSetList ordinaryGroupingSetList) {
        for (int i = 0; i < ordinaryGroupingSetList.size(); i++) {
            generate(ordinaryGroupingSetList.get(i));
            if (i < ordinaryGroupingSetList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <cube list> ::= CUBE <left paren> <ordinary grouping set list> <right paren>
    private void generate(CubeList cubeList) {
        append(TokenType.CUBE.getContent());
        append(TokenType.LEFT_PAREN.getContent());
        generate(cubeList.getOrdinaryGroupingSetList());
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <grouping sets specification> ::= GROUPING SETS <left paren> <grouping set list> <right paren>
    private void generate(GroupingSetsSpecification groupingSetsSpecification) {
        append(TokenType.GROUPING.getContent());
        append(' ');
        append("SETS");
        append(TokenType.LEFT_PAREN.getContent());
        generate(groupingSetsSpecification.getGroupingSetList());
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <grouping set list> ::= <grouping set> [ { <comma> <grouping set> }... ]
    private void generate(GroupingSetList groupingSetList) {
        for (int i = 0; i < groupingSetList.size(); i++) {
            generate(groupingSetList.get(i));
            if (i < groupingSetList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <grouping set>
    // ::= <ordinary grouping set>
    //   | <rollup list>
    //   | <cube list>
    //   | <grouping sets specification>
    //   | <empty grouping set>
    private void generate(GroupingSet groupingSet) {
        if (groupingSet instanceof OrdinaryGroupingSet) {
            generate((OrdinaryGroupingSet) groupingSet);
            return;
        }
        if (groupingSet instanceof RollupList) {
            generate((RollupList) groupingSet);
            return;
        }
        if (groupingSet instanceof CubeList) {
            generate((CubeList) groupingSet);
            return;
        }
        if (groupingSet instanceof GroupingSetsSpecification) {
            generate((GroupingSetsSpecification) groupingSet);
            return;
        }
        if (groupingSet instanceof EmptyGroupingSet) {
            generate((EmptyGroupingSet) groupingSet);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), groupingSet.getBeginIndex(), "This grouping set is not supported, " + groupingSet.getClass().getName());
    }

    // <empty grouping set> ::= <left paren> <right paren>
    private void generate(EmptyGroupingSet emptyGroupingSet) {
        append(TokenType.LEFT_PAREN.getContent());
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <having clause> ::= HAVING <search condition>
    private void generate(HavingClause havingClause) {
        append(TokenType.HAVING.getContent());
        append(' ');
        generate(havingClause.getSearchCondition());
    }

    // <window clause> ::= WINDOW <window definition list>
    private void generate(WindowClause windowClause) {
        append(TokenType.WINDOW.getContent());
        append(' ');
        generate(windowClause.getWindowDefinitionList());
    }

    // <window definition list> ::= <window definition> [ { <comma> <window definition> }... ]
    private void generate(WindowDefinitionList windowDefinitionList) {
        for (int i = 0; i < windowDefinitionList.size(); i++) {
            generate(windowDefinitionList.get(i));
            if (i < windowDefinitionList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <window definition> ::= <new window name> AS <window specification>
    private void generate(WindowDefinition windowDefinition) {
        generate(windowDefinition.getNewWindowName());
        append(' ');
        append(TokenType.AS.getContent());
        append(' ');
        generate(windowDefinition.getWindowSpecification());
    }

    // <window specification>
    // ::=
    // <left paren>
    // [ <existing window name> ]
    // [ <window partition clause> ]
    // [ <window order clause> ]
    // [ <window frame clause> ]
    // <right paren>
    private void generate(WindowSpecification windowSpecification) {
        append(TokenType.LEFT_PAREN.getContent());
        boolean flag = false;
        Identifier existingWindowName = windowSpecification.getExistingWindowName();
        if (existingWindowName != null) {
            generate(existingWindowName);
            flag = true;
        }
        WindowPartitionClause windowPartitionClause = windowSpecification.getWindowPartitionClause();
        if (windowPartitionClause != null) {
            if (flag == true) {
                append(' ');
            }
            generate(windowPartitionClause);
            flag = true;
        }
        WindowOrderClause windowOrderClause = windowSpecification.getWindowOrderClause();
        if (windowOrderClause != null) {
            if (flag == true) {
                append(' ');
            }
            generate(windowOrderClause);
            flag = true;
        }
        WindowFrameClause windowFrameClause = windowSpecification.getWindowFrameClause();
        if (windowFrameClause != null) {
            if (flag == true) {
                append(' ');
            }
            generate(windowFrameClause);
        }
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <window partition clause> ::= PARTITION BY <window partition column reference list>
    private void generate(WindowPartitionClause windowPartitionClause) {
        append(TokenType.PARTITION.getContent());
        append(' ');
        append(TokenType.BY.getContent());
        append(' ');
        generate(windowPartitionClause.getWindowPartitionColumnReferenceList());
    }

    // <window partition column reference list>
    // ::=
    // <window partition column reference> [ { <comma> <window partition column reference> }... ]
    private void generate(WindowPartitionColumnReferenceList windowPartitionColumnReferenceList) {
        for (int i = 0; i < windowPartitionColumnReferenceList.size(); i++) {
            generate(windowPartitionColumnReferenceList.get(i));
            if (i < windowPartitionColumnReferenceList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <window partition column reference> ::= <column reference> [ <collate clause> ]
    private void generate(WindowPartitionColumnReference windowPartitionColumnReference) {
        generate(windowPartitionColumnReference.getColumnReference());
        CollateClause collateClause = windowPartitionColumnReference.getCollateClause();
        if (collateClause != null) {
            append(' ');
            generate(collateClause);
        }
    }

    // <window order clause> ::= ORDER BY <sort specification list>
    private void generate(WindowOrderClause windowOrderClause) {
        append(TokenType.ORDER.getContent());
        append(' ');
        append(TokenType.BY.getContent());
        append(' ');
        generate(windowOrderClause.getSortSpecificationList());
    }

    // <window frame clause> ::= <window frame units> <window frame extent> [ <window frame exclusion> ]
    private void generate(WindowFrameClause windowFrameClause) {
        generate(windowFrameClause.getWindowFrameUnits());
        append(' ');
        generate(windowFrameClause.getWindowFrameExtent());
        WindowFrameExclusion windowFrameExclusion = windowFrameClause.getWindowFrameExclusion();
        if (windowFrameExclusion != null) {
            append(' ');
            generate(windowFrameExclusion);
        }
    }

    // <window frame units> ::= ROWS | RANGE
    private void generate(WindowFrameUnits windowFrameUnits) {
        if (windowFrameUnits.isRows()) {
            append(TokenType.ROWS.getContent());
        } else if (windowFrameUnits.isRange()) {
            append(TokenType.RANGE.getContent());
        } else {
            throw new YuliaException(getSql(), getLineNumber(), windowFrameUnits.getBeginIndex(), "This window frame units is not supported.");
        }
    }

    // <window frame extent> ::= <window frame start> | <window frame between>
    private void generate(WindowFrameExtent windowFrameExtent) {
        if (windowFrameExtent instanceof WindowFrameStart) {
            generate((WindowFrameStart) windowFrameExtent);
            return;
        }
        if (windowFrameExtent instanceof WindowFrameBetween) {
            generate((WindowFrameBetween) windowFrameExtent);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), windowFrameExtent.getBeginIndex(), "This window frame extent is not supported, " + windowFrameExtent.getClass().getName());
    }

    // <window frame start> ::= UNBOUNDED PRECEDING | <window frame preceding> | CURRENT ROW
    private void generate(WindowFrameStart windowFrameStart) {
        if (windowFrameStart instanceof UnboundedPreceding) {
            generate((UnboundedPreceding) windowFrameStart);
            return;
        }
        if (windowFrameStart instanceof WindowFramePreceding) {
            generate((WindowFramePreceding) windowFrameStart);
            return;
        }
        if (windowFrameStart instanceof CurrentRow) {
            generate((CurrentRow) windowFrameStart);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), windowFrameStart.getBeginIndex(), "This window frame start is not supported, " + windowFrameStart.getClass().getName());
    }

    // UNBOUNDED PRECEDING
    private void generate(UnboundedPreceding unboundedPreceding) {
        append("UNBOUNDED");
        append(' ');
        append("PRECEDING");
    }

    // <window frame preceding> ::= <unsigned value specification> PRECEDING
    private void generate(WindowFramePreceding windowFramePreceding) {
        generate(windowFramePreceding.getUnsignedValueSpecification());
        append(' ');
        append("PRECEDING");
    }

    // <unsigned value specification> ::= <unsigned literal> | <general value specification>
    private void generate(UnsignedValueSpecification unsignedValueSpecification) {
        if (unsignedValueSpecification instanceof UnsignedLiteral) {
            generate((UnsignedLiteral) unsignedValueSpecification);
            return;
        }
        if (unsignedValueSpecification instanceof GeneralValueSpecification) {
            generate((GeneralValueSpecification) unsignedValueSpecification);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), unsignedValueSpecification.getBeginIndex(), "This unsigned value specification is not supported, " + unsignedValueSpecification.getClass().getName());
    }

    // <unsigned literal> ::= <unsigned numeric literal> | <general literal>
    private void generate(UnsignedLiteral unsignedLiteral) {
        if (unsignedLiteral instanceof UnsignedNumericLiteral) {
            generate((UnsignedNumericLiteral) unsignedLiteral);
            return;
        }
        if (unsignedLiteral instanceof GeneralLiteral) {
            generate((GeneralLiteral) unsignedLiteral);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), unsignedLiteral.getBeginIndex(), "This unsigned literal is not supported, " + unsignedLiteral.getClass().getName());
    }

    // CURRENT ROW
    private void generate(CurrentRow currentRow) {
        append(TokenType.CURRENT.getContent());
        append(' ');
        append(TokenType.ROW.getContent());
    }

    // <window frame between> ::= BETWEEN <window frame bound 1> AND <window frame bound 2>
    private void generate(WindowFrameBetween windowFrameBetween) {
        append(TokenType.BETWEEN.getContent());
        append(' ');
        generate(windowFrameBetween.getWindowFrameBound1());
        append(TokenType.AND.getContent());
        append(' ');
        generate(windowFrameBetween.getWindowFrameBound2());
    }

    // <window frame bound>
    // ::= <window frame start>
    //   | UNBOUNDED FOLLOWING
    //   | <window frame following>
    private void generate(WindowFrameBound windowFrameBound) {
        if (windowFrameBound instanceof WindowFrameStart) {
            generate((WindowFrameStart) windowFrameBound);
            return;
        }
        if (windowFrameBound instanceof UnboundedFollowing) {
            generate((UnboundedFollowing) windowFrameBound);
            return;
        }
        if (windowFrameBound instanceof WindowFrameFollowing) {
            generate((WindowFrameFollowing) windowFrameBound);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), windowFrameBound.getBeginIndex(), "This window frame bound is not supported, " + windowFrameBound.getClass().getName());
    }

    // UNBOUNDED FOLLOWING
    private void generate(UnboundedFollowing unboundedFollowing) {
        append("UNBOUNDED");
        append(' ');
        append("FOLLOWING");
    }

    // <window frame following> ::= <unsigned value specification> FOLLOWING
    private void generate(WindowFrameFollowing windowFrameFollowing) {
        generate(windowFrameFollowing.getUnsignedValueSpecification());
        append(' ');
        append("FOLLOWING");
    }

    // <window frame exclusion>
    // ::= EXCLUDE CURRENT ROW
    //   | EXCLUDE GROUP
    //   | EXCLUDE TIES
    //   | EXCLUDE NO OTHERS
    private void generate(WindowFrameExclusion windowFrameExclusion) {
        append("EXCLUDE");
        append(' ');
        if (windowFrameExclusion.isExcludeCurrentRow()) {
            append(TokenType.CURRENT.getContent());
            append(' ');
            append(TokenType.ROW.getContent());
        } else if (windowFrameExclusion.isExcludeGroup()) {
            append(TokenType.GROUP.getContent());
        } else if (windowFrameExclusion.isExcludeTies()) {
            append("TIES");
        } else if (windowFrameExclusion.isExcludeNoOthers()) {
            append(TokenType.NO.getContent());
            append(' ');
            append("OTHERS");
        } else {
            throw new YuliaException(getSql(), getLineNumber(), windowFrameExclusion.getBeginIndex(), "This window frame exclusion is not supported.");
        }
    }

    // <from clause> ::= FROM <table reference list>
    private void generate(FromClause fromClause) {
        append(TokenType.FROM.getContent());
        append(' ');
        TableReferenceList tableReferenceList = fromClause.getTableReferenceList();
        generate(tableReferenceList);
    }

    // <table reference list> ::= <table reference> [ { <comma> <table reference> }... ]
    private void generate(TableReferenceList tableReferenceList) {
        for (int i = 0; i < tableReferenceList.size(); i++) {
            generate(tableReferenceList.get(i));
            if (i < tableReferenceList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <table reference> ::= <table primary or joined table> [ <sample clause> ]
    private void generate(TableReference tableReference) {
        generate(tableReference.getTablePrimaryOrJoinedTable());
        SampleClause sampleClause = tableReference.getSampleClause();
        if (sampleClause != null) {
            append(' ');
            generate(sampleClause);
        }
    }

    // <table primary or joined table> ::= <table primary> | <joined table>
    private void generate(TablePrimaryOrJoinedTable tablePrimaryOrJoinedTable) {
        if (tablePrimaryOrJoinedTable instanceof TablePrimary) {
            generate((TablePrimary) tablePrimaryOrJoinedTable);
            return;
        }
        if (tablePrimaryOrJoinedTable instanceof JoinedTable) {
            generate((JoinedTable) tablePrimaryOrJoinedTable);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), tablePrimaryOrJoinedTable.getBeginIndex(), "This table primary or joined table is not supported, " + tablePrimaryOrJoinedTable.getClass().getName());
    }

    // <table primary>
    // ::=
    //   <table or query name> [ [ AS ] <correlation name> [ <left paren> <derived column list> <right paren> ] ]
    // | <derived table> [ AS ] <correlation name> [ <left paren> <derived column list> <right paren> ]
    // | <lateral derived table> [ AS ] <correlation name> [ <left paren> <derived column list> <right paren> ]
    // | <collection derived table> [ AS ] <correlation name> [ <left paren> <derived column list> <right paren> ]
    // | <table function derived table> [ AS ] <correlation name> [ <left paren> <derived column list> <right paren> ]
    // | <only spec> [ [ AS ] <correlation name> [ <left paren> <derived column list> <right paren> ] ]
    // | <left paren> <joined table> <right paren>
    private void generate(TablePrimary tablePrimary) {
        if (tablePrimary instanceof TableOrQueryNameTablePrimary) {
            throw new RuntimeException("TODO");
        }
        if (tablePrimary instanceof DerivedTableTablePrimary) {
            throw new RuntimeException("TODO");
        }
        if (tablePrimary instanceof LateralDerivedTableTablePrimary) {
            throw new RuntimeException("TODO");
        }
        if (tablePrimary instanceof CollectionDerivedTableTablePrimary) {
            throw new RuntimeException("TODO");
        }
        if (tablePrimary instanceof TableFunctionDerivedTableTablePrimary) {
            throw new RuntimeException("TODO");
        }
        if (tablePrimary instanceof OnlySpecTablePrimary) {
            throw new RuntimeException("TODO");
        }
        if (tablePrimary instanceof ParenthesizedJoinedTableTablePrimary) {
            throw new RuntimeException("TODO");
        }
        throw new YuliaException(getSql(), getLineNumber(), tablePrimary.getBeginIndex(), "This table primary is not supported, " + tablePrimary.getClass().getName());
    }

    // <joined table>
    // ::=
    //   <cross join>
    // | <qualified join>
    // | <natural join>
    // | <union join>
    private void generate(JoinedTable joinedTable) {
        if (joinedTable instanceof CrossJoin) {
            generate((CrossJoin) joinedTable);
            return;
        }
        if (joinedTable instanceof QualifiedJoin) {
            generate((QualifiedJoin) joinedTable);
            return;
        }
        if (joinedTable instanceof NaturalJoin) {
            generate((NaturalJoin) joinedTable);
        }
        if (joinedTable instanceof UnionJoin) {
            generate((UnionJoin) joinedTable);
        }
        throw new YuliaException(getSql(), getLineNumber(), joinedTable.getBeginIndex(), "This joined table is not supported, " + joinedTable.getClass().getName());
    }

    // <cross join> ::= <table reference> CROSS JOIN <table primary>
    private void generate(CrossJoin crossJoin) {
        generate(crossJoin.getTableReference());
        append(' ');
        append(TokenType.CROSS.getContent());
        append(' ');
        append(TokenType.JOIN.getContent());
        append(' ');
        generate(crossJoin.getTablePrimary());
    }

    // <qualified join> ::= <table reference> [ <join type> ] JOIN <table reference> <join specification>
    private void generate(QualifiedJoin qualifiedJoin) {
        generate(qualifiedJoin.getTableReference1());
        append(' ');
        JoinType joinType = qualifiedJoin.getJoinType();
        if (joinType != null) {
            generate(qualifiedJoin.getJoinType());
            append(' ');
        }
        append(TokenType.JOIN.getContent());
        append(' ');
        generate(qualifiedJoin.getTableReference2());
        append(' ');
        generate(qualifiedJoin.getJoinSpecification());
    }

    // <join specification> ::= <join condition> | <named columns join>
    private void generate(JoinSpecification joinSpecification) {
        if (joinSpecification instanceof JoinCondition) {
            generate((JoinCondition) joinSpecification);
            return;
        }
        if (joinSpecification instanceof NamedColumnsJoin) {
            generate((NamedColumnsJoin) joinSpecification);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), joinSpecification.getBeginIndex(), "This join specification is not supported, " + joinSpecification.getClass().getName());
    }

    // <join condition> ::= ON <search condition>
    private void generate(JoinCondition joinCondition) {
        append(TokenType.ON.getContent());
        append(' ');
        generate(joinCondition.getSearchCondition());
    }

    // <named columns join> ::= USING <left paren> <join column list> <right paren>
    private void generate(NamedColumnsJoin namedColumnsJoin) {
        append(TokenType.USING.getContent());
        append(TokenType.LEFT_PAREN.getContent());
        generate(namedColumnsJoin.getJoinColumnList());
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <join type> ::= INNER | <outer join type> [ OUTER ]
    private void generate(JoinType joinType) {
        if (joinType.isInner()) {
            append(TokenType.INNER.getContent());
            return;
        }
        if (joinType.isLeftOuter()) {
            append(TokenType.LEFT.getContent());
            append(' ');
            append(TokenType.OUTER.getContent());
            return;
        }
        if (joinType.isRightOuter()) {
            append(TokenType.RIGHT.getContent());
            append(' ');
            append(TokenType.OUTER.getContent());
            return;
        }
        if (joinType.isFullOuter()) {
            append(TokenType.FULL.getContent());
            append(' ');
            append(TokenType.OUTER.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), joinType.getBeginIndex(), "This join type is not supported, " + joinType.getClass().getName());
    }

    // <natural join> ::= <table reference> NATURAL [ <join type> ] JOIN <table primary>
    private void generate(NaturalJoin naturalJoin) {
        generate(naturalJoin.getTableReference());
        append(' ');
        append(TokenType.NATURAL.getContent());
        append(' ');
        JoinType joinType = naturalJoin.getJoinType();
        if (joinType != null) {
            generate(naturalJoin.getJoinType());
            append(' ');
        }
        append(TokenType.JOIN.getContent());
        append(' ');
        generate(naturalJoin.getTablePrimary());
    }

    // <union join> ::= <table reference> UNION JOIN <table primary>
    private void generate(UnionJoin unionJoin) {
        generate(unionJoin.getTableReference());
        append(' ');
        append(TokenType.UNION.getContent());
        append(' ');
        append(TokenType.JOIN.getContent());
        append(' ');
        generate(unionJoin.getTablePrimary());
    }

    // <sample clause>
    // ::=
    // TABLESAMPLE
    // <sample method>
    // <left paren> <sample percentage> <right paren>
    // [ <repeatable clause> ]
    private void generate(SampleClause sampleClause) {
        append("TABLESAMPLE");
        append(' ');
        generate(sampleClause.getSampleMethod());
        append(TokenType.LEFT_PAREN.getContent());
        generate(sampleClause.getSamplePercentage());
        append(TokenType.RIGHT_PAREN.getContent());
        RepeatableClause repeatableClause = sampleClause.getRepeatableClause();
        if (repeatableClause != null) {
            append(' ');
            generate(repeatableClause);
        }
    }

    // <sample method> ::= BERNOULLI | SYSTEM
    private void generate(SampleMethod sampleMethod) {
        if (sampleMethod.isBernoulli()) {
            append("BERNOULLI");
            return;
        }
        if (sampleMethod.isSystem()) {
            append(TokenType.SYSTEM.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), sampleMethod.getBeginIndex(), "This sample method is not supported, " + sampleMethod.getClass().getName());
    }

    // <numeric value expression>
    // ::= <term>
    //   | <numeric value expression> <plus sign> <term>
    //   | <numeric value expression> <minus sign> <term>
    private void generate(NumericValueExpression numericValueExpression) {
        if (numericValueExpression instanceof Term) {
            generate((Term) numericValueExpression);
            return;
        }
        if (numericValueExpression instanceof PlusTerm) {
            generate((PlusTerm) numericValueExpression);
            return;
        }
        if (numericValueExpression instanceof MinusTerm) {
            generate((MinusTerm) numericValueExpression);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), numericValueExpression.getBeginIndex(), "This numeric value expression is not supported, " + numericValueExpression.getClass().getName());
    }

    // <term>
    // ::=
    //   <factor>
    // | <term> <asterisk> <factor>
    // | <term> <solidus> <factor>
    private void generate(Term term) {
        if (term instanceof Factor) {
            generate((Factor) term);
            return;
        }
        if (term instanceof AsteriskFactor) {
            generate((AsteriskFactor) term);
            return;
        }
        if (term instanceof SolidusFactor) {
            generate((SolidusFactor) term);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), term.getBeginIndex(), "This term is not supported, " + term.getClass().getName());
    }

    // <factor> ::= [ <sign> ] <numeric primary>
    private void generate(Factor factor) {
        Sign sign = factor.getSign();
        if (sign != null) {
            if (sign instanceof PlusSign) {
                append(TokenType.PLUS_SIGN.getContent());
            } else if (sign instanceof MinusSign) {
                append(TokenType.MINUS_SIGN.getContent());
            } else {
                throw new YuliaException(getSql(), getLineNumber(), sign.getBeginIndex(), "This sign is not supported, " + sign.getClass().getName());
            }
        }
        generate(factor.getNumericPrimary());
    }

    // <numeric primary>
    // ::= <value expression primary>
    //   | <numeric value function>
    private void generate(NumericPrimary numericPrimary) {
        if (numericPrimary instanceof ValueExpressionPrimary) {
            generate((ValueExpressionPrimary) numericPrimary);
            return;
        }
        if (numericPrimary instanceof NumericValueFunction) {
            generate((NumericValueFunction) numericPrimary);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), numericPrimary.getBeginIndex(), "This numeric primary is not supported, " + numericPrimary.getClass().getName());
    }

    // <numeric value function>
    // ::=
    //   <position expression>
    // | <extract expression>
    // | <length expression>
    // | <cardinality expression>
    // | <absolute value expression>
    // | <modulus expression>
    // | <natural logarithm>
    // | <exponential function>
    // | <power function>
    // | <square root>
    // | <floor function>
    // | <ceiling function>
    // | <width bucket function>
    private void generate(NumericValueFunction numericValueFunction) {
        if (numericValueFunction instanceof PositionExpression) {
            throw new RuntimeException("TODO");
        }
        if (numericValueFunction instanceof ExtractExpression) {
            throw new RuntimeException("TODO");
        }
        if (numericValueFunction instanceof LengthExpression) {
            throw new RuntimeException("TODO");
        }
        if (numericValueFunction instanceof CardinalityExpression) {
            throw new RuntimeException("TODO");
        }
        if (numericValueFunction instanceof AbsoluteValueExpression) {
            throw new RuntimeException("TODO");
        }
        if (numericValueFunction instanceof ModulusExpression) {
            throw new RuntimeException("TODO");
        }
        if (numericValueFunction instanceof NaturalLogarithm) {
            throw new RuntimeException("TODO");
        }
        if (numericValueFunction instanceof ExponentialFunction) {
            throw new RuntimeException("TODO");
        }
        if (numericValueFunction instanceof PowerFunction) {
            throw new RuntimeException("TODO");
        }
        if (numericValueFunction instanceof SquareRoot) {
            throw new RuntimeException("TODO");
        }
        if (numericValueFunction instanceof FloorFunction) {
            throw new RuntimeException("TODO");
        }
        if (numericValueFunction instanceof CeilingFunction) {
            throw new RuntimeException("TODO");
        }
        if (numericValueFunction instanceof WidthBucketFunction) {
            throw new RuntimeException("TODO");
        }
        throw new YuliaException(getSql(), getLineNumber(), numericValueFunction.getBeginIndex(), "This numeric value function is not supported, " + numericValueFunction.getClass().getName());
    }

    // <term> <asterisk> <factor>
    private void generate(AsteriskFactor asteriskFactor) {
        generate(asteriskFactor.getTerm());
        append(TokenType.ASTERISK.getContent());
        generate(asteriskFactor.getFactor());
    }

    // <term> <solidus> <factor>
    private void generate(SolidusFactor solidusFactor) {
        generate(solidusFactor.getTerm());
        append(TokenType.SOLIDUS.getContent());
        generate(solidusFactor.getFactor());
    }

    // <numeric value expression> <plus sign> <term>
    private void generate(PlusTerm plusTerm) {
        generate(plusTerm.getNumericValueExpression());
        append(TokenType.PLUS_SIGN.getContent());
        generate(plusTerm.getTerm());
    }

    // <numeric value expression> <minus sign> <term>
    private void generate(MinusTerm minusTerm) {
        generate(minusTerm.getNumericValueExpression());
        append(TokenType.MINUS_SIGN.getContent());
        generate(minusTerm.getTerm());
    }

    // <repeatable clause> ::= REPEATABLE <left paren> <repeat argument> <right paren>
    private void generate(RepeatableClause repeatableClause) {
        append("REPEATABLE");
        append(TokenType.LEFT_PAREN.getContent());
        generate(repeatableClause.getRepeatArgument());
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <release savepoint statement> ::= RELEASE SAVEPOINT <savepoint specifier>
    private void generate(ReleaseSavepointStatement releaseSavepointStatement) {
        append(TokenType.RELEASE.getContent());
        append(' ');
        append(TokenType.SAVEPOINT.getContent());
        append(' ');
        generate(releaseSavepointStatement.getSavepointSpecifier());
    }

    // <return statement> ::= RETURN <return value>
    private void generate(ReturnStatement returnStatement) {
        append(TokenType.RETURN.getContent());
        append(' ');
        generate(returnStatement.getReturnValue());
    }

    // <return value> ::= <value expression> | NULL
    private void generate(ReturnValue returnValue) {
        ValueExpression valueExpression = returnValue.getValueExpression();
        if (valueExpression == null) {
            append(TokenType.NULL.getContent());
            return;
        }
        generate(valueExpression);
    }

    // <revoke privilege statement>
    // ::=
    // REVOKE
    // [ <revoke option extension> ]
    // <privileges>
    // FROM <grantee> [ { <comma> <grantee> }... ]
    // [ GRANTED BY <grantor> ] <drop behavior>
    private void generate(RevokePrivilegeStatement revokePrivilegeStatement) {
        append(TokenType.REVOKE.getContent());
        append(' ');
        if (revokePrivilegeStatement.isGrantOptionFor()) {
            append(TokenType.GRANT.getContent());
            append(' ');
            append("OPTION");
            append(TokenType.FOR.getContent());
            append(' ');
        } else if (revokePrivilegeStatement.isHierarchyOptionFor()) {
            append("HIERARCHY");
            append(' ');
            append("OPTION");
            append(TokenType.FOR.getContent());
            append(' ');
        }
        generate(revokePrivilegeStatement.getPrivileges());
        append(' ');
        append(TokenType.FROM.getContent());
        append(' ');
        generate(revokePrivilegeStatement.getGranteeList());
        append(' ');
        Grantor grantor = revokePrivilegeStatement.getGrantor();
        if (grantor != null) {
            append("GRANTED");
            append(' ');
            append(TokenType.BY.getContent());
            append(' ');
            generate(grantor);
            append(' ');
        }
        generate(revokePrivilegeStatement.getDropBehavior());
    }

    // <privileges> ::= <object privileges> ON <object name>
    private void generate(Privileges privileges) {
        generate(privileges.getObjectPrivileges());
        append(' ');
        append(TokenType.ON.getContent());
        append(' ');
        generate(privileges.getObjectName());
    }

    // <object privileges>
    // ::= ALL PRIVILEGES
    //   | <action> [ { <comma> <action> }... ]
    private void generate(ObjectPrivileges objectPrivileges) {
        if (objectPrivileges instanceof AllPrivileges) {
            append(TokenType.ALL.getContent());
            append(' ');
            append("PRIVILEGES");
            return;
        }
        if (objectPrivileges instanceof ActionList) {
            generate((ActionList) objectPrivileges);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), objectPrivileges.getBeginIndex(), "This object privileges is not supported, " + objectPrivileges.getClass().getName());
    }

    // <action> [ { <comma> <action> }... ]
    private void generate(ActionList actionList) {
        for (int i = 0; i < actionList.size(); i++) {
            generate(actionList.get(i));
            if (i < actionList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <action>
    // ::= SELECT
    //   | SELECT <left paren> <privilege column list> <right paren>
    //   | SELECT <left paren> <privilege method list> <right paren>
    //   | DELETE
    //   | INSERT [ <left paren> <privilege column list> <right paren> ]
    //   | UPDATE [ <left paren> <privilege column list> <right paren> ]
    //   | REFERENCES [ <left paren> <privilege column list> <right paren> ]
    //   | USAGE
    //   | TRIGGER
    //   | UNDER
    //   | EXECUTE
    private void generate(Action action) {
        if (action instanceof SelectAction) {
            append(TokenType.SELECT.getContent());
            return;
        }
        if (action instanceof SelectPrivilegeColumnListAction) {
            append(TokenType.SELECT.getContent());
            append(TokenType.LEFT_PAREN.getContent());
            SelectPrivilegeColumnListAction selectPrivilegeColumnListAction
                    = (SelectPrivilegeColumnListAction) action;
            generate(selectPrivilegeColumnListAction.getPrivilegeColumnList());
            append(TokenType.RIGHT_PAREN.getContent());
            return;
        }
        if (action instanceof SelectPrivilegeMethodListAction) {
            append(TokenType.SELECT.getContent());
            append(TokenType.LEFT_PAREN.getContent());
            SelectPrivilegeMethodListAction selectPrivilegeMethodListAction
                    = (SelectPrivilegeMethodListAction) action;
            for (int i = 0; i < selectPrivilegeMethodListAction.size(); i++) {
                generate(selectPrivilegeMethodListAction.get(i));
                if (i < selectPrivilegeMethodListAction.size() - 1) {
                    append(TokenType.COMMA.getContent());
                    append(' ');
                }
            }
            append(TokenType.RIGHT_PAREN.getContent());
            return;
        }
        if (action instanceof DeleteAction) {
            append(TokenType.DELETE.getContent());
            return;
        }
        if (action instanceof InsertPrivilegeColumnListAction) {
            append(TokenType.INSERT.getContent());
            append(TokenType.LEFT_PAREN.getContent());
            InsertPrivilegeColumnListAction insertPrivilegeColumnListAction
                    = (InsertPrivilegeColumnListAction) action;
            generate(insertPrivilegeColumnListAction.getPrivilegeColumnList());
            append(TokenType.RIGHT_PAREN.getContent());
            return;
        }
        if (action instanceof UpdatePrivilegeColumnListAction) {
            append(TokenType.INSERT.getContent());
            append(TokenType.LEFT_PAREN.getContent());
            UpdatePrivilegeColumnListAction updatePrivilegeColumnListAction
                    = (UpdatePrivilegeColumnListAction) action;
            generate(updatePrivilegeColumnListAction.getPrivilegeColumnList());
            append(TokenType.RIGHT_PAREN.getContent());
            return;
        }
        if (action instanceof ReferencesPrivilegeColumnListAction) {
            append(TokenType.REFERENCES.getContent());
            append(TokenType.LEFT_PAREN.getContent());
            ReferencesPrivilegeColumnListAction referencesPrivilegeColumnListAction
                    = (ReferencesPrivilegeColumnListAction) action;
            generate(referencesPrivilegeColumnListAction.getPrivilegeColumnList());
            append(TokenType.RIGHT_PAREN.getContent());
            return;
        }
        if (action instanceof UsageAction) {
            append("USAGE");
            return;
        }
        if (action instanceof TriggerAction) {
            append(TokenType.TRIGGER.getContent());
            return;
        }
        if (action instanceof UnderAction) {
            append("UNDER");
            return;
        }
        if (action instanceof ExecuteAction) {
            append(TokenType.EXECUTE.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), action.getBeginIndex(), "This action is not supported, " + action.getClass().getName());
    }

    // <specific routine designator>
    // ::= SPECIFIC <routine type> <specific name>
    //   | <routine type> <member name> [ FOR <schema-resolved user-defined type name> ]
    private void generate(SpecificRoutineDesignator specificRoutineDesignator) {
        if (specificRoutineDesignator instanceof SpecificRoutineDesignatorSubtype1) {
            generate((SpecificRoutineDesignatorSubtype1) specificRoutineDesignator);
            return;
        }
        if (specificRoutineDesignator instanceof SpecificRoutineDesignatorSubtype2) {
            generate((SpecificRoutineDesignatorSubtype2) specificRoutineDesignator);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), specificRoutineDesignator.getBeginIndex(), "This specific routine designator is not supported, " + specificRoutineDesignator.getClass().getName());
    }

    // SPECIFIC <routine type> <specific name>
    private void generate(SpecificRoutineDesignatorSubtype1 specificRoutineDesignatorSubtype1) {
        append(TokenType.SPECIFIC.getContent());
        append(' ');
        generate(specificRoutineDesignatorSubtype1.getRoutineType());
        append(' ');
        generate(specificRoutineDesignatorSubtype1.getSpecificName());
    }

    // <routine type>
    // ::= ROUTINE
    //   | FUNCTION
    //   | PROCEDURE
    //   | [ INSTANCE | STATIC | CONSTRUCTOR ] METHOD
    private void generate(RoutineType routineType) {
        if (routineType.isRoutine()) {
            append("ROUTINE");
            return;
        }
        if (routineType.isFunction()) {
            append(TokenType.FUNCTION.getContent());
            return;
        }
        if (routineType.isProcedure()) {
            append(TokenType.PROCEDURE.getContent());
            return;
        }
        if (routineType.isInstanceMethod()) {
            append("INSTANCE");
            append(' ');
            append(TokenType.METHOD.getContent());
            return;
        }
        if (routineType.isStaticMethod()) {
            append(TokenType.STATIC.getContent());
            append(' ');
            append(TokenType.METHOD.getContent());
            return;
        }
        if (routineType.isConstructorMethod()) {
            append("CONSTRUCTOR");
            append(' ');
            append(TokenType.METHOD.getContent());
            return;
        }
        if (routineType.isMethod()) {
            append(TokenType.METHOD.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), routineType.getBeginIndex(), "This routine type is not supported.");
    }

    // <routine type> <member name> [ FOR <schema-resolved user-defined type name> ]
    private void generate(SpecificRoutineDesignatorSubtype2 specificRoutineDesignatorSubtype2) {
        generate(specificRoutineDesignatorSubtype2.getRoutineType());
        append(' ');
        generate(specificRoutineDesignatorSubtype2.getMemberNameAlternatives());
        DataTypeList dataTypeList = specificRoutineDesignatorSubtype2.getDataTypeList();
        if (dataTypeList != null) {
            append(' ');
            generate(dataTypeList);
        }
        SchemaQualifiedName schemaResolvedUserDefinedTypeName
                = specificRoutineDesignatorSubtype2.getSchemaResolvedUserDefinedTypeName();
        if (schemaResolvedUserDefinedTypeName != null) {
            append(' ');
            append(TokenType.FOR.getContent());
            append(' ');
            generate(schemaResolvedUserDefinedTypeName);
        }
    }

    // <member name alternatives> ::= <schema qualified routine name> | <method name>
    private void generate(MemberNameAlternatives memberNameAlternatives) {
        if (memberNameAlternatives instanceof SchemaQualifiedName) {
            generate((SchemaQualifiedName) memberNameAlternatives);
            return;
        }
        if (memberNameAlternatives instanceof Identifier) {
            generate((Identifier) memberNameAlternatives);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), memberNameAlternatives.getBeginIndex(), "This member name alternatives is not supported, " + memberNameAlternatives.getClass().getName());
    }

    // <object name>
    // ::= [ TABLE ] <table name>
    //   | DOMAIN <domain name>
    //   | COLLATION <collation name>
    //   | CHARACTER SET <character set name>
    //   | TRANSLATION <transliteration name>
    //   | TYPE <schema-resolved user-defined type name>
    //   | SEQUENCE <sequence generator name>
    //   | <specific routine designator>
    private void generate(ObjectName objectName) {
        if (objectName instanceof TableObjectName) {
            TableObjectName tableObjectName = (TableObjectName) objectName;
            if (tableObjectName.isTable()) {
                append(TokenType.TABLE.getContent());
                append(' ');
            }
            generate(tableObjectName.getTableName());
            return;
        }
        if (objectName instanceof DomainObjectName) {
            append("DOMAIN");
            append(' ');
            DomainObjectName domainObjectName = (DomainObjectName) objectName;
            SchemaQualifiedName domainName = domainObjectName.getDomainName();
            generate(domainName);
            return;
        }
        if (objectName instanceof CollationObjectName) {
            append("COLLATION");
            append(' ');
            CollationObjectName collationObjectName = (CollationObjectName) objectName;
            generate(collationObjectName.getCollationName());
            return;
        }
        if (objectName instanceof CharacterSetObjectName) {
            append(TokenType.CHARACTER.getContent());
            append(' ');
            append(TokenType.SET.getContent());
            append(' ');
            CharacterSetObjectName characterSetObjectName = (CharacterSetObjectName) objectName;
            generate(characterSetObjectName.getCharacterSetName());
            return;
        }
        if (objectName instanceof TranslationObjectName) {
            append(TokenType.TRANSLATION.getContent());
            append(' ');
            TranslationObjectName translationObjectName = (TranslationObjectName) objectName;
            generate(translationObjectName.getTranslationName());
            return;
        }
        if (objectName instanceof TypeObjectName) {
            append("TYPE");
            append(' ');
            TypeObjectName typeObjectName = (TypeObjectName) objectName;
            generate(typeObjectName.getSchemaResolvedUserDefinedTypeName());
            return;
        }
        if (objectName instanceof SequenceObjectName) {
            append("SEQUENCE");
            append(' ');
            SequenceObjectName sequenceObjectName = (SequenceObjectName) objectName;
            generate(sequenceObjectName.getSequenceGeneratorName());
            return;
        }
        if (objectName instanceof SpecificRoutineDesignator) {
            generate((SpecificRoutineDesignator) objectName);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), objectName.getBeginIndex(), "This object name is not supported, " + objectName.getClass().getName());
    }

    // <local or schema qualified name> ::= [ <local or schema qualifier> <period> ] <qualified identifier>
    private void generate(LocalOrSchemaQualifiedName localOrSchemaQualifiedName) {
        if (localOrSchemaQualifiedName.isModule()) {
            append(TokenType.MODULE.getContent());
            append(TokenType.PERIOD.getContent());
        } else {
            SchemaName schemaName = localOrSchemaQualifiedName.getSchemaName();
            if (schemaName != null) {
                generate(schemaName);
                append(TokenType.PERIOD.getContent());
            }
        }
        generate(localOrSchemaQualifiedName.getQualifiedIdentifier());
    }

    // <schema qualified name> ::= [ <schema name> <period> ] <qualified identifier>
    private void generate(SchemaQualifiedName schemaQualifiedName) {
        SchemaName schemaName = schemaQualifiedName.getSchemaName();
        if (schemaName != null) {
            generate(schemaName);
            append(TokenType.PERIOD.getContent());
        }
        generate(schemaQualifiedName.getQualifiedIdentifier());
    }

    // <character set name> ::= [ <schema name> <period> ] <SQL language identifier>
    private void generate(CharacterSetName characterSetName) {
        SchemaName schemaName = characterSetName.getSchemaName();
        if (schemaName != null) {
            generate(schemaName);
            append(TokenType.PERIOD.getContent());
        }
        generate(characterSetName.getSqlLanguageIdentifier());
    }

    // <grantee> [ { <comma> <grantee> }... ]
    private void generate(GranteeList granteeList) {
        for (int i = 0; i < granteeList.size(); i++) {
            generate(granteeList.get(i));
            if (i < granteeList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <grantee> ::= PUBLIC | <authorization identifier>
    private void generate(Grantee grantee) {
        if (grantee.isPublic()) {
            append("PUBLIC");
            return;
        }
        Identifier authorizationIdentifier = grantee.getAuthorizationIdentifier();
        generate(authorizationIdentifier);
    }

    // <grantor> ::= CURRENT_USER | CURRENT_ROLE
    private void generate(Grantor grantor) {
        if (grantor.isCurrentUser()) {
            append(TokenType.CURRENT_USER.getContent());
            return;
        }
        if (grantor.isCurrentRole()) {
            append(TokenType.CURRENT_ROLE.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), grantor.getBeginIndex(), "This grantor is not supported, " + grantor.getClass().getName());
    }

    // <drop behavior> ::= CASCADE | RESTRICT
    private void generate(DropBehavior dropBehavior) {
        if (dropBehavior.isCascade()) {
            append("CASCADE");
            return;
        }
        if (dropBehavior.isRestrict()) {
            append("RESTRICT");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), dropBehavior.getBeginIndex(), "This drop behavior is not supported, " + dropBehavior.getClass().getName());
    }

    // <revoke role statement>
    // ::=
    // REVOKE
    // [ ADMIN OPTION FOR ]
    // <role revoked> [ { <comma> <role revoked> }... ]
    // FROM <grantee> [ { <comma> <grantee> }... ]
    // [ GRANTED BY <grantor> ]
    // <drop behavior>
    private void generate(RevokeRoleStatement revokeRoleStatement) {
        append(TokenType.REVOKE.getContent());
        append(' ');
        if (revokeRoleStatement.isAdminOptionFor()) {
            append("ADMIN");
            append(' ');
            append("OPTION");
            append(' ');
            append(TokenType.FOR.getContent());
            append(' ');
        }
        generate(revokeRoleStatement.getRoleRevokedList());
        append(' ');
        append(TokenType.FROM.getContent());
        append(' ');
        generate(revokeRoleStatement.getGranteeList());
        append(' ');
        Grantor grantor = revokeRoleStatement.getGrantor();
        if (grantor != null) {
            append("GRANTED");
            append(' ');
            append(TokenType.BY.getContent());
            append(' ');
            generate(grantor);
            append(' ');
        }
        generate(revokeRoleStatement.getDropBehavior());
    }

    // <rollback statement> ::= ROLLBACK [ WORK ] [ AND [ NO ] CHAIN ] [ <savepoint clause> ]
    private void generate(RollbackStatement rollbackStatement) {
        append(TokenType.ROLLBACK.getContent());
        append(' ');
        if (rollbackStatement.isWork()) {
            append("WORK");
            append(' ');
        }
        if (rollbackStatement.isAndChain()) {
            append(TokenType.AND.getContent());
            append(' ');
            append("CHAIN");
            append(' ');
        } else if (rollbackStatement.isAndNoChain()) {
            append(TokenType.AND.getContent());
            append(' ');
            append(TokenType.NO.getContent());
            append(' ');
            append("CHAIN");
            append(' ');
        }
        append(TokenType.TO.getContent());
        append(' ');
        append(TokenType.SAVEPOINT.getContent());
        append(' ');
        generate(rollbackStatement.getSavepointSpecifier());
    }

    // <savepoint statement> ::= SAVEPOINT <savepoint specifier>
    private void generate(SavepointStatement savepointStatement) {
        append(TokenType.SAVEPOINT.getContent());
        append(' ');
        generate(savepointStatement.getSavepointSpecifier());
    }

    // <schema definition>
    // ::=
    // CREATE SCHEMA <schema name clause>
    // [ <schema character set or path> ]
    // [ <schema element> ... ]
    private void generate(SchemaDefinition schemaDefinition) {
        append(TokenType.CREATE.getContent());
        append(' ');
        append("SCHEMA");
        append(' ');
        generate(schemaDefinition.getSchemaNameClause());
        SchemaCharacterSetOrPath schemaCharacterSetOrPath = schemaDefinition.getSchemaCharacterSetOrPath();
        if (schemaCharacterSetOrPath != null) {
            append(' ');
            generate(schemaCharacterSetOrPath);
        }
        SchemaElementList schemaElementList = schemaDefinition.getSchemaElementList();
        if (schemaElementList != null) {
            append(' ');
            generate(schemaElementList);
        }
    }

    // <schema name clause>
    // ::= <schema name>
    //   | AUTHORIZATION <schema authorization identifier>
    //   | <schema name> AUTHORIZATION <schema authorization identifier>
    private void generate(SchemaNameClause schemaNameClause) {
        SchemaName schemaName = schemaNameClause.getSchemaName();
        if (schemaName != null) {
            generate(schemaName);
            Identifier schemaAuthorizationIdentifier = schemaNameClause.getAuthorizationSchemaAuthorizationIdentifier();
            if (schemaAuthorizationIdentifier != null) {
                append(' ');
                append(TokenType.AUTHORIZATION.getContent());
                append(' ');
                generate(schemaAuthorizationIdentifier);
            }
            return;
        }
        append(TokenType.AUTHORIZATION.getContent());
        append(' ');
        Identifier schemaAuthorizationIdentifier = schemaNameClause.getAuthorizationSchemaAuthorizationIdentifier();
        generate(schemaAuthorizationIdentifier);
    }

    // <schema name> ::= [ <catalog name> <period> ] <unqualified schema name>
    private void generate(SchemaName schemaName) {
        CatalogName catalogName = schemaName.getCatalogName();
        if (catalogName != null) {
            generate(catalogName);
            append(TokenType.PERIOD.getContent());
        }
        generate(schemaName.getUnqualifiedSchemaName());
    }

    // <catalog name> ::= <identifier>
    private void generate(CatalogName catalogName) {
        generate(catalogName.getCatalogName());
    }

    // <schema character set or path>
    // ::= <schema character set specification>
    //   | <schema path specification>
    //   | <schema character set specification> <schema path specification>
    //   | <schema path specification> <schema character set specification>
    private void generate(SchemaCharacterSetOrPath schemaCharacterSetOrPath) {
        ShemaCharacterSetSpecification shemaCharacterSetSpecification
                = schemaCharacterSetOrPath.getShemaCharacterSetSpecification();
        PathSpecification schemaPathSpecification
                = schemaCharacterSetOrPath.getSchemaPathSpecification();
        if (shemaCharacterSetSpecification != null) {
            generate(shemaCharacterSetSpecification);
            if (schemaPathSpecification != null) {
                append(' ');
                generate(schemaPathSpecification);
            }
            return;
        }
        if (schemaPathSpecification != null) {
            generate(schemaPathSpecification);
            if (shemaCharacterSetSpecification != null) {
                append(' ');
                generate(shemaCharacterSetSpecification);
            }
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), schemaCharacterSetOrPath.getBeginIndex(), "This schema character set or path is not supported.");
    }

    // <schema character set specification> ::= DEFAULT CHARACTER SET <character set specification>
    private void generate(ShemaCharacterSetSpecification shemaCharacterSetSpecification) {
        append(TokenType.DEFAULT.getContent());
        append(' ');
        append(TokenType.CHARACTER.getContent());
        append(' ');
        append(TokenType.SET.getContent());
        append(' ');
        generate(shemaCharacterSetSpecification.getCharacterSetSpecification());
    }

    // <path specification> ::= PATH <schema name list>
    private void generate(PathSpecification pathSpecification) {
        append("PATH");
        append(' ');
        generate(pathSpecification.getSchemaNameList());
    }

    // <schema name list> ::= <schema name> [ { <comma> <schema name> }... ]
    private void generate(SchemaNameList schemaNameList) {
        for (int i = 0; i < schemaNameList.size(); i++) {
            generate(schemaNameList.get(i));
            if (i < schemaNameList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <schema element> ...
    private void generate(SchemaElementList schemaElementList) {
        for (int i = 0; i < schemaElementList.size(); i++) {
            generate(schemaElementList.get(i));
            if (i < schemaElementList.size() - 1) {
                append(' ');
            }
        }
    }

    // <schema element>
    // ::= <table definition>
    //   | <view definition>
    //   | <domain definition>
    //   | <character set definition>
    //   | <collation definition>
    //   | <transliteration definition>
    //   | <assertion definition>
    //   | <trigger definition>
    //   | <user-defined type definition>
    //   | <user-defined cast definition>
    //   | <user-defined ordering definition>
    //   | <transform definition>
    //   | <schema routine>
    //   | <sequence generator definition>
    //   | <grant statement>
    //   | <role definition>
    private void generate(SchemaElement schemaElement) {
        if (schemaElement instanceof TableDefinition) {
            throw new RuntimeException("TODO");
        }
        if (schemaElement instanceof ViewDefinition) {
            throw new RuntimeException("TODO");
        }
        if (schemaElement instanceof DomainDefinition) {
            throw new RuntimeException("TODO");
        }
        if (schemaElement instanceof CharacterSetDefinition) {
            throw new RuntimeException("TODO");
        }
        if (schemaElement instanceof CollationDefinition) {
            throw new RuntimeException("TODO");
        }
        if (schemaElement instanceof TransliterationDefinition) {
            throw new RuntimeException("TODO");
        }
        if (schemaElement instanceof AssertionDefinition) {
            throw new RuntimeException("TODO");
        }
        if (schemaElement instanceof TriggerDefinition) {
            throw new RuntimeException("TODO");
        }
        if (schemaElement instanceof UserDefinedTypeDefinition) {
            throw new RuntimeException("TODO");
        }
        if (schemaElement instanceof UserDefinedCastDefinition) {
            throw new RuntimeException("TODO");
        }
        if (schemaElement instanceof UserDefinedOrderingDefinition) {
            throw new RuntimeException("TODO");
        }
        if (schemaElement instanceof TransformDefinition) {
            throw new RuntimeException("TODO");
        }
        if (schemaElement instanceof SchemaRoutine) {
            throw new RuntimeException("TODO");
        }
        if (schemaElement instanceof SequenceGeneratorDefinition) {
            throw new RuntimeException("TODO");
        }
        if (schemaElement instanceof GrantStatement) {
            throw new RuntimeException("TODO");
        }
        if (schemaElement instanceof RoleDefinition) {
            throw new RuntimeException("TODO");
        }
        throw new YuliaException(getSql(), getLineNumber(), schemaElement.getBeginIndex(), "This schema element is not supported, " + schemaElement.getClass().getName());
    }

    // <schema function> ::= CREATE <SQL-invoked function>
    private void generate(SchemaFunction schemaFunction) {
        append(TokenType.CREATE.getContent());
        append(' ');
        FunctionSpecification functionSpecification = schemaFunction.getFunctionSpecification();
        if (functionSpecification != null) {
            generate(functionSpecification);
        } else {
            generate(schemaFunction.getMethodSpecificationDesignator());
        }
        append(' ');
        generate(schemaFunction.getRoutineBody());
    }

    // <function specification>
    // ::=
    // FUNCTION
    // <schema qualified routine name>
    // <SQL parameter declaration list>
    // <returns clause>
    // <routine characteristics>
    // [ <dispatch clause> ]
    private void generate(FunctionSpecification functionSpecification) {
        append(TokenType.FUNCTION.getContent());
        append(' ');
        generate(functionSpecification.getSchemaQualifiedRoutineName());
        append(' ');
        generate(functionSpecification.getSqlParameterDeclarationList());
        append(' ');
        generate(functionSpecification.getReturnsClause());
        RoutineCharacteristics routineCharacteristics
                = functionSpecification.getRoutineCharacteristics();
        if (routineCharacteristics != null && !routineCharacteristics.isEmpty()) {
            append(' ');
            generate(routineCharacteristics);
        }
        DispatchClause dispatchClause = functionSpecification.getDispatchClause();
        if (dispatchClause != null) {
            append(' ');
            generate(dispatchClause);
        }
    }

    // <routine characteristics> ::= [ <routine characteristic> ... ]
    private void generate(RoutineCharacteristics routineCharacteristics) {
        for (int i = 0; i < routineCharacteristics.size(); i++) {
            generate(routineCharacteristics.get(i));
            if (i < routineCharacteristics.size() - 1) {
                append(' ');
            }
        }
    }

    // <routine characteristic>
    // ::= <language clause>
    //   | <parameter style clause>
    //   | SPECIFIC <specific name>
    //   | <deterministic characteristic>
    //   | <SQL-data access indication>
    //   | <null-call clause>
    //   | <dynamic result sets characteristic>
    //   | <savepoint level indication>
    private void generate(RoutineCharacteristic routineCharacteristic) {
        if (routineCharacteristic instanceof LanguageClause) {
            generate((LanguageClause) routineCharacteristic);
            return;
        }
        if (routineCharacteristic instanceof ParameterStyleClause) {
            generate((ParameterStyleClause) routineCharacteristic);
            return;
        }
        if (routineCharacteristic instanceof SpecificSpecificName) {
            generate((SpecificSpecificName) routineCharacteristic);
            return;
        }
        if (routineCharacteristic instanceof DeterministicCharacteristic) {
            generate((DeterministicCharacteristic) routineCharacteristic);
            return;
        }
        if (routineCharacteristic instanceof SqlDataAccessIndication) {
            generate((SqlDataAccessIndication) routineCharacteristic);
            return;
        }
        if (routineCharacteristic instanceof NullCallClause) {
            generate((NullCallClause) routineCharacteristic);
            return;
        }
        if (routineCharacteristic instanceof DynamicResultSetsCharacteristic) {
            generate((DynamicResultSetsCharacteristic) routineCharacteristic);
            return;
        }
        if (routineCharacteristic instanceof SavepointLevelIndication) {
            generate((SavepointLevelIndication) routineCharacteristic);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), routineCharacteristic.getBeginIndex(), "This routine characteristic is not supported, " + routineCharacteristic.getClass().getName());
    }

    // SPECIFIC <specific name>
    private void generate(SpecificSpecificName specificSpecificName) {
        append(TokenType.SPECIFIC.getContent());
        append(' ');
        generate(specificSpecificName.getSpecificName());
    }

    // <savepoint level indication> ::= NEW SAVEPOINT LEVEL | OLD SAVEPOINT LEVEL
    private void generate(SavepointLevelIndication savepointLevelIndication) {
        if (savepointLevelIndication.isNewSavepointLevel()) {
            append(TokenType.NEW.getContent());
        } else if (savepointLevelIndication.isOldSavepointLevel()) {
            append(TokenType.OLD.getContent());
        } else {
            throw new YuliaException(getSql(), getLineNumber(), savepointLevelIndication.getBeginIndex(), "This savepoint level indication is not supported.");
        }
        append(' ');
        append(TokenType.SAVEPOINT.getContent());
        append(' ');
        append("LEVEL");
    }

    // <dispatch clause> ::= STATIC DISPATCH
    private void generate(DispatchClause dispatchClause) {
        append(TokenType.STATIC.getContent());
        append(' ');
        append("DISPATCH");
    }

    // <method specification designator>
    // ::= SPECIFIC METHOD <specific method name>
    //   | [ INSTANCE | STATIC | CONSTRUCTOR ]
    //     METHOD
    //     <method name>
    //     <SQL parameter declaration list>
    //     [ <returns clause> ]
    //     FOR
    //     <schema-resolved user-defined type name>
    private void generate(MethodSpecificationDesignator methodSpecificationDesignator) {
        if (methodSpecificationDesignator instanceof MethodSpecificationDesignatorSubtype1) {
            generate((MethodSpecificationDesignatorSubtype1) methodSpecificationDesignator);
            return;
        }
        if (methodSpecificationDesignator instanceof MethodSpecificationDesignatorSubtype1) {
            generate((MethodSpecificationDesignatorSubtype2) methodSpecificationDesignator);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), methodSpecificationDesignator.getBeginIndex(), "This method specification designator is not supported, " + methodSpecificationDesignator.getClass().getName());
    }

    // SPECIFIC METHOD <specific method name>
    private void generate(MethodSpecificationDesignatorSubtype1 methodSpecificationDesignatorSubtype1) {
        append(TokenType.SPECIFIC.getContent());
        append(' ');
        append(TokenType.METHOD.getContent());
        append(' ');
        generate(methodSpecificationDesignatorSubtype1.getSpecificMethodName());
    }

    // [ INSTANCE | STATIC | CONSTRUCTOR ]
    // METHOD
    // <method name>
    // <SQL parameter declaration list>
    // [ <returns clause> ]
    // FOR
    // <schema-resolved user-defined type name>
    private void generate(MethodSpecificationDesignatorSubtype2 methodSpecificationDesignatorSubtype2) {
        if (methodSpecificationDesignatorSubtype2.isInstance()) {
            append("INSTANCE");
        } else if (methodSpecificationDesignatorSubtype2.isStatic()) {
            append(TokenType.STATIC.getContent());
        } else if (methodSpecificationDesignatorSubtype2.isConstructor()) {
            append("CONSTRUCTOR");
        } else {
            throw new YuliaException(getSql(), getLineNumber(), methodSpecificationDesignatorSubtype2.getBeginIndex(), "This is not supported.");
        }
        append(' ');
        append(TokenType.METHOD.getContent());
        append(' ');
        generate(methodSpecificationDesignatorSubtype2.getMethodName());
        append(' ');
        generate(methodSpecificationDesignatorSubtype2.getSqlParameterDeclarationList());
        append(' ');
        ReturnsClause returnsClause = methodSpecificationDesignatorSubtype2.getReturnsClause();
        if (returnsClause != null) {
            generate(returnsClause);
            append(' ');
        }
        append(TokenType.FOR.getContent());
        append(' ');
        generate(methodSpecificationDesignatorSubtype2.getSchemaResolvedUserDefinedTypeName());
    }

    // <routine body> ::= <SQL routine spec> | <external body reference>
    private void generate(RoutineBody routineBody) {
        if (routineBody instanceof SqlRoutineSpec) {
            generate((SqlRoutineSpec) routineBody);
            return;
        }
        if (routineBody instanceof ExternalBodyReference) {
            generate((ExternalBodyReference) routineBody);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), routineBody.getBeginIndex(), "This routine body is not supported, " + routineBody.getClass().getName());
    }

    // <SQL routine spec> ::= [ <rights clause> ] <SQL routine body>
    private void generate(SqlRoutineSpec sqlRoutineSpec) {
        RightsClause rightsClause = sqlRoutineSpec.getRightsClause();
        if (rightsClause != null) {
            generate(rightsClause);
            append(' ');
        }
        generate(sqlRoutineSpec.getSqlRoutineBody());
    }

    // <rights clause> ::= SQL SECURITY INVOKER | SQL SECURITY DEFINER
    private void generate(RightsClause rightsClause) {
        append(TokenType.SQL.getContent());
        append(' ');
        append("SECURITY");
        append(' ');
        if (rightsClause.isSqlSecurityInvoker()) {
            append("INVOKER");
            return;
        }
        if (rightsClause.isSqlSecurityDefiner()) {
            append("DEFINER");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), rightsClause.getBeginIndex(), "This right clause is not supported, " + rightsClause.getClass().getName());
    }

    // <SQL executable statement>
    // ::= <SQL schema statement>
    //   | <SQL data statement>
    //   | <SQL control statement>
    //   | <SQL transaction statement>
    //   | <SQL connection statement>
    //   | <SQL session statement>
    //   | <SQL diagnostics statement>
    //   | <SQL dynamic statement>
    private void generate(SqlExecutableStatement sqlExecutableStatement) {
        if (sqlExecutableStatement instanceof SqlSchemaStatement) {
            generate((SqlSchemaStatement) sqlExecutableStatement);
            return;
        }
        if (sqlExecutableStatement instanceof SqlDataStatement) {
            generate((SqlDataStatement) sqlExecutableStatement);
            return;
        }
        if (sqlExecutableStatement instanceof SqlControlStatement) {
            generate((SqlControlStatement) sqlExecutableStatement);
            return;
        }
        if (sqlExecutableStatement instanceof SqlTransactionStatement) {
            generate((SqlTransactionStatement) sqlExecutableStatement);
            return;
        }
        if (sqlExecutableStatement instanceof SqlConnectionStatement) {
            generate((SqlConnectionStatement) sqlExecutableStatement);
            return;
        }
        if (sqlExecutableStatement instanceof SqlSessionStatement) {
            generate((SqlSessionStatement) sqlExecutableStatement);
            return;
        }
        if (sqlExecutableStatement instanceof GetDiagnosticsStatement) {
            generate((GetDiagnosticsStatement) sqlExecutableStatement);
            return;
        }
        if (sqlExecutableStatement instanceof SqlDynamicStatement) {
            generate((SqlDynamicStatement) sqlExecutableStatement);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), sqlExecutableStatement.getBeginIndex(), "This SQL executable statement is not supported, " + sqlExecutableStatement.getClass().getName());
    }

    // <SQL schema statement>
    // ::= <SQL schema definition statement>
    //   | <SQL schema manipulation statement>
    private void generate(SqlSchemaStatement sqlSchemaStatement) {
        if (sqlSchemaStatement instanceof SqlSchemaDefinitionStatement) {
            generate((SqlSchemaDefinitionStatement) sqlSchemaStatement);
            return;
        }
        if (sqlSchemaStatement instanceof SqlSchemaManipulationStatement) {
            generate((SqlSchemaManipulationStatement) sqlSchemaStatement);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), sqlSchemaStatement.getBeginIndex(), "This SQL schema statement is not supported, " + sqlSchemaStatement.getClass().getName());
    }

    // <SQL schema definition statement>
    // ::= <schema definition>
    //   | <table definition>
    //   | <view definition>
    //   | <SQL-invoked routine>
    //   | <grant statement>
    //   | <role definition>
    //   | <domain definition>
    //   | <character set definition>
    //   | <collation definition>
    //   | <transliteration definition>
    //   | <assertion definition>
    //   | <trigger definition>
    //   | <user-defined type definition>
    //   | <user-defined cast definition>
    //   | <user-defined ordering definition>
    //   | <transform definition>
    //   | <sequence generator definition>
    private void generate(SqlSchemaDefinitionStatement sqlSchemaDefinitionStatement) {
        throw new RuntimeException("TODO");
    }

    // <SQL schema manipulation statement>
    // ::= <drop schema statement>
    //   | <alter table statement>
    //   | <drop table statement>
    //   | <drop view statement>
    //   | <alter routine statement>
    //   | <drop routine statement>
    //   | <drop user-defined cast statement>
    //   | <revoke statement>
    //   | <drop role statement>
    //   | <alter domain statement>
    //   | <drop domain statement>
    //   | <drop character set statement>
    //   | <drop collation statement>
    //   | <drop transliteration statement>
    //   | <drop assertion statement>
    //   | <drop trigger statement>
    //   | <alter type statement>
    //   | <drop data type statement>
    //   | <drop user-defined ordering statement>
    //   | <alter transform statement>
    //   | <drop transform statement>
    //   | <alter sequence generator statement>
    //   | <drop sequence generator statement>
    private void generate(SqlSchemaManipulationStatement sqlSchemaManipulationStatement) {
        throw new RuntimeException("TODO");
    }

    // <SQL data statement>
    // ::= <open statement>
    //   | <fetch statement>
    //   | <close statement>
    //   | <select statement: single row>
    //   | <free locator statement>
    //   | <hold locator statement>
    //   | <SQL data change statement>
    private void generate(SqlDataStatement sqlDataStatement) {
        if (sqlDataStatement instanceof OpenStatement) {
            generate((OpenStatement) sqlDataStatement);
            return;
        }
        if (sqlDataStatement instanceof FetchStatement) {
            generate((FetchStatement) sqlDataStatement);
            return;
        }
        if (sqlDataStatement instanceof CloseStatement) {
            generate((CloseStatement) sqlDataStatement);
            return;
        }
        if (sqlDataStatement instanceof SelectStatementSingleRow) {
            generate((SelectStatementSingleRow) sqlDataStatement);
            return;
        }
        if (sqlDataStatement instanceof FreeLocatorStatement) {
            generate((FreeLocatorStatement) sqlDataStatement);
            return;
        }
        if (sqlDataStatement instanceof HoldLocatorStatement) {
            generate((HoldLocatorStatement) sqlDataStatement);
            return;
        }
        if (sqlDataStatement instanceof SqlDataChangeStatement) {
            generate((SqlDataChangeStatement) sqlDataStatement);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), sqlDataStatement.getBeginIndex(), "This SQL data statement is not supported, " + sqlDataStatement.getClass().getName());
    }

    // <select statement: single row>
    // ::=
    // SELECT
    // [ <set quantifier> ]
    // <select list>
    // INTO
    // <select target list>
    // <table expression>
    private void generate(SelectStatementSingleRow selectStatementSingleRow) {
        append(TokenType.SELECT.getContent());
        append(' ');
        SetQuantifier setQuantifier = selectStatementSingleRow.getSetQuantifier();
        if (setQuantifier != null) {
            generate(setQuantifier);
            append(' ');
        }
        generate(selectStatementSingleRow.getSelectList());
        append(' ');
        append(TokenType.INTO.getContent());
        append(' ');
        generate(selectStatementSingleRow.getSelectTargetList());
        append(' ');
        generate(selectStatementSingleRow.getTableExpression());
    }

    // <select target list> ::= <target specification> [ { <comma> <target specification> }... ]
    private void generate(SelectTargetList selectTargetList) {
        for (int i = 0; i < selectTargetList.size(); i++) {
            generate(selectTargetList.get(i));
            if (i < selectTargetList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <SQL data change statement>
    // ::= <delete statement: positioned>
    //   | <delete statement: searched>
    //   | <insert statement>
    //   | <update statement: positioned>
    //   | <update statement: searched>
    //   | <merge statement>
    private void generate(SqlDataChangeStatement sqlDataChangeStatement) {
        throw new RuntimeException("TODO");
    }

    // <SQL control statement>
    // ::= <call statement>
    //   | <return statement>
    private void generate(SqlControlStatement sqlControlStatement) {
        if (sqlControlStatement instanceof CallStatement) {
            generate((CallStatement) sqlControlStatement);
            return;
        }
        if (sqlControlStatement instanceof ReturnStatement) {
            generate((ReturnStatement) sqlControlStatement);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), sqlControlStatement.getBeginIndex(), "This SQL control statement is not supported, " + sqlControlStatement.getClass().getName());
    }

    // <call statement> ::= CALL <routine invocation>
    private void generate(CallStatement callStatement) {
        append(TokenType.CALL.getContent());
        append(' ');
        generate(callStatement.getRoutineInvocation());
    }

    // <routine invocation> ::= <routine name> <SQL argument list>
    private void generate(RoutineInvocation routineInvocation) {
        generate(routineInvocation.getRoutineName());
        generate(routineInvocation.getSqlArgumentList());
    }

    // <SQL argument list>
    // ::=
    // <left paren>
    // [ <SQL argument> [ { <comma> <SQL argument> }... ] ]
    // <right paren>
    private void generate(SqlArgumentList sqlArgumentList) {
        append(TokenType.LEFT_PAREN.getContent());
        if (!sqlArgumentList.isEmpty()) {
            for (int i = 0; i < sqlArgumentList.size(); i++) {
                generate(sqlArgumentList.get(i));
                if (i < sqlArgumentList.size() - 1) {
                    append(TokenType.COMMA.getContent());
                    append(' ');
                }
            }
        }
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <SQL argument>
    // ::= <value expression>
    //   | <generalized expression>
    //   | <target specification>
    private void generate(SqlArgument sqlArgument) {
        if (sqlArgument instanceof ValueExpression) {
            generate((ValueExpression) sqlArgument);
            return;
        }
        if (sqlArgument instanceof GeneralizedExpression) {
            generate((GeneralizedExpression) sqlArgument);
            return;
        }
        if (sqlArgument instanceof TargetSpecification) {
            generate((TargetSpecification) sqlArgument);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), sqlArgument.getBeginIndex(), "This SQL argument is not supported, " + sqlArgument.getClass().getName());
    }

    // <generalized expression> ::= <value expression> AS <path-resolved user-defined type name>
    private void generate(GeneralizedExpression generalizedExpression) {
        generate(generalizedExpression.getValueExpression());
        append(' ');
        append(TokenType.AS.getContent());
        append(' ');
        generate(generalizedExpression.getPathResolvedUserDefinedTypeName());
    }

    // <SQL transaction statement>
    // ::= <start transaction statement>
    //   | <set transaction statement>
    //   | <set constraints mode statement>
    //   | <savepoint statement>
    //   | <release savepoint statement>
    //   | <commit statement>
    //   | <rollback statement>
    private void generate(SqlTransactionStatement sqlTransactionStatement) {
        throw new RuntimeException("TODO");
    }

    // <SQL connection statement>
    // ::= <connect statement>
    //   | <set connection statement>
    //   | <disconnect statement>
    private void generate(SqlConnectionStatement sqlConnectionStatement) {
        if (sqlConnectionStatement instanceof ConnectStatement) {
            generate((ConnectStatement) sqlConnectionStatement);
            return;
        }
        if (sqlConnectionStatement instanceof SetConnectionStatement) {
            generate((SetConnectionStatement) sqlConnectionStatement);
            return;
        }
        if (sqlConnectionStatement instanceof DisconnectStatement) {
            generate((DisconnectStatement) sqlConnectionStatement);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), sqlConnectionStatement.getBeginIndex(), "This SQL connection statement is not supported, " + sqlConnectionStatement.getClass().getName());
    }

    // <SQL session statement>
    // ::= <set session user identifier statement>
    //   | <set role statement>
    //   | <set local time zone statement>
    //   | <set session characteristics statement>
    //   | <set catalog statement>
    //   | <set schema statement>
    //   | <set names statement>
    //   | <set path statement>
    //   | <set transform group statement>
    //   | <set session collation statement>
    private void generate(SqlSessionStatement sqlSessionStatement) {
        if (sqlSessionStatement instanceof SetSessionUserIdentifierStatement) {
            generate((SetSessionUserIdentifierStatement) sqlSessionStatement);
            return;
        }
        if (sqlSessionStatement instanceof SetRoleStatement) {
            generate((SetRoleStatement) sqlSessionStatement);
            return;
        }
        if (sqlSessionStatement instanceof SetLocalTimeZoneStatement) {
            generate((SetLocalTimeZoneStatement) sqlSessionStatement);
            return;
        }
        if (sqlSessionStatement instanceof SetSessionCharacteristicsStatement) {
            generate((SetSessionCharacteristicsStatement) sqlSessionStatement);
            return;
        }
        if (sqlSessionStatement instanceof SetCatalogStatement) {
            generate((SetCatalogStatement) sqlSessionStatement);
            return;
        }
        if (sqlSessionStatement instanceof SetSchemaStatement) {
            generate((SetSchemaStatement) sqlSessionStatement);
            return;
        }
        if (sqlSessionStatement instanceof SetNamesStatement) {
            generate((SetNamesStatement) sqlSessionStatement);
            return;
        }
        if (sqlSessionStatement instanceof SetPathStatement) {
            generate((SetPathStatement) sqlSessionStatement);
            return;
        }
        if (sqlSessionStatement instanceof SetTransformGroupStatement) {
            generate((SetTransformGroupStatement) sqlSessionStatement);
            return;
        }
        if (sqlSessionStatement instanceof SetSessionCollationStatement) {
            generate((SetSessionCollationStatement) sqlSessionStatement);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), sqlSessionStatement.getBeginIndex(), "This SQL session statement is not supported, " + sqlSessionStatement.getClass().getName());
    }

    // <set session collation statement>
    // ::= SET COLLATION <collation specification> [ FOR <character set specification list> ]
    //   | SET NO COLLATION [ FOR <character set specification list> ]
    private void generate(SetSessionCollationStatement setSessionCollationStatement) {
        if (setSessionCollationStatement instanceof SetSessionCollationStatementSubtype1) {
            generate((SetSessionCollationStatementSubtype1) setSessionCollationStatement);
            return;
        }
        if (setSessionCollationStatement instanceof SetSessionCollationStatementSubtype2) {
            generate((SetSessionCollationStatementSubtype2) setSessionCollationStatement);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), setSessionCollationStatement.getBeginIndex(), "This set session collation statement is not supported, " + setSessionCollationStatement.getClass().getName());
    }

    // <SQL dynamic statement>
    private void generate(SqlDynamicStatement sqlDynamicStatement) {
        throw new RuntimeException("TODO");
    }

    // <external body reference>
    // ::= EXTERNAL
    //     [ NAME <external routine name> ]
    //     [ <parameter style clause> ]
    //     [ <transform group specification> ]
    //     [ <external security clause> ]
    private void generate(ExternalBodyReference externalBodyReference) {
        append(TokenType.EXTERNAL.getContent());
        ExternalRoutineName externalRoutineName = externalBodyReference.getExternalRoutineName();
        if (externalRoutineName != null) {
            append(' ');
            append("NAME");
            append(' ');
            generate(externalRoutineName);
        }
        ParameterStyleClause parameterStyleClause = externalBodyReference.getParameterStyleClause();
        if (parameterStyleClause != null) {
            append(' ');
            generate(parameterStyleClause);
        }
        TransformGroupSpecification transformGroupSpecification = externalBodyReference.getTransformGroupSpecification();
        if (transformGroupSpecification != null) {
            append(' ');
            generate(transformGroupSpecification);
        }
        ExternalSecurityClause externalSecurityClause = externalBodyReference.getExternalSecurityClause();
        if (externalSecurityClause != null) {
            append(' ');
            generate(externalSecurityClause);
        }
    }

    // <external routine name> ::= <identifier> | <character string literal>
    private void generate(ExternalRoutineName externalRoutineName) {
        if (externalRoutineName instanceof Identifier) {
            generate((Identifier) externalRoutineName);
            return;
        }
        if (externalRoutineName instanceof CharacterStringLiteral) {
            generate((CharacterStringLiteral) externalRoutineName);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), externalRoutineName.getBeginIndex(), "This external routine name is not supported, " + externalRoutineName.getClass().getName());
    }

    // <character string literal>
    // ::=
    // [ <introducer> <character set specification> ]
    // <quote> [ <character representation> ... ] <quote>
    // [ { <separator> <quote> [ <character representation> ... ] <quote> }... ]
    private void generate(CharacterStringLiteral characterStringLiteral) {
        if (characterStringLiteral.isIntroducer()) {
            append('_');
            append(' ');
            CharacterSetName characterSetSpecification
                    = characterStringLiteral.getCharacterSetSpecification();
            generate(characterSetSpecification);
            append(' ');
        }
        StringList stringList = characterStringLiteral.getStringList();
        for (int i = 0; i < stringList.size(); i++) {
            append('\'');
            append(stringList.get(i).getContent());
            append('\'');
            if (i < stringList.size() - 1) {
                append(' ');
            }
        }
    }

    // <parameter style clause> ::= PARAMETER STYLE <parameter style>
    private void generate(ParameterStyleClause parameterStyleClause) {
        append(TokenType.PARAMETER.getContent());
        append(' ');
        append("STYLE");
        append(' ');
        if (parameterStyleClause.isSql()) {
            append(TokenType.SQL.getContent());
            return;
        }
        if (parameterStyleClause.isGeneral()) {
            append("GENERAL");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), parameterStyleClause.getBeginIndex(), "This parameter style clause is not supported, " + parameterStyleClause.getClass().getName());
    }

    // <transform group specification>
    // ::=
    // TRANSFORM
    // GROUP
    // { <single group specification> | <multiple group specification> }
    private void generate(TransformGroupSpecification transformGroupSpecification) {
        append("TRANSFORM");
        append(' ');
        append(TokenType.GROUP.getContent());
        append(' ');
        Identifier singleGroupSpecification
                = transformGroupSpecification.getSingleGroupSpecification();
        if (singleGroupSpecification != null) {
            generate(singleGroupSpecification);
            return;
        }
        MultipleGroupSpecification multipleGroupSpecification
                = transformGroupSpecification.getMultipleGroupSpecification();
        if (multipleGroupSpecification != null) {
            generate(multipleGroupSpecification);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), transformGroupSpecification.getBeginIndex(), "This transform group specification is not supported, " + transformGroupSpecification.getClass().getName());
    }

    // <multiple group specification> ::= <group specification> [ { <comma> <group specification> }... ]
    private void generate(MultipleGroupSpecification multipleGroupSpecification) {
        for (int i = 0; i < multipleGroupSpecification.size(); i++) {
            generate(multipleGroupSpecification.get(i));
            if (i < multipleGroupSpecification.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <group specification> ::= <group name> FOR TYPE <path-resolved user-defined type name>
    private void generate(GroupSpecification groupSpecification) {
        generate(groupSpecification.getGroupName());
        append(TokenType.FOR.getContent());
        append(' ');
        append("TYPE");
        append(' ');
        generate(groupSpecification.getPathResolvedUserDefinedTypeName());
    }

    // <external security clause>
    // ::= EXTERNAL SECURITY DEFINER
    //   | EXTERNAL SECURITY INVOKER
    //   | EXTERNAL SECURITY IMPLEMENTATION DEFINED
    private void generate(ExternalSecurityClause externalSecurityClause) {
        append(TokenType.EXTERNAL.getContent());
        append(' ');
        append("SECURITY");
        append(' ');
        if (externalSecurityClause.isExternalSecurityDefiner()) {
            append("DEFINER");
            return;
        }
        if (externalSecurityClause.isExternalSecurityInvoker()) {
            append("INVOKER");
            return;
        }
        if (externalSecurityClause.isExternalSecurityImplementationDefined()) {
            append("IMPLEMENTATION");
            append(' ');
            append("DEFINED");
        }
        throw new YuliaException(getSql(), getLineNumber(), externalSecurityClause.getBeginIndex(), "This external security clause is not supported, " + externalSecurityClause.getClass().getName());
    }

    // <schema procedure>
    // ::=
    // CREATE
    // PROCEDURE
    // <schema qualified routine name>
    // <SQL parameter declaration list>
    // <routine characteristics>
    // <routine body>
    private void generate(SchemaProcedure schemaProcedure) {
        append(TokenType.CREATE.getContent());
        append(' ');
        append(TokenType.PROCEDURE.getContent());
        append(' ');
        generate(schemaProcedure.getSchemaQualifiedRoutineName());
        append(' ');
        generate(schemaProcedure.getSqlParameterDeclarationList());
        append(' ');
        generate(schemaProcedure.getRoutineCharacteristics());
        append(' ');
        generate(schemaProcedure.getRoutineBody());
    }

    // <set catalog statement> ::= SET <catalog name characteristic>
    // <catalog name characteristic> ::= CATALOG <value specification>
    private void generate(SetCatalogStatement setCatalogStatement) {
        append(TokenType.SET.getContent());
        append(' ');
        append("CATALOG");
        append(' ');
        generate(setCatalogStatement.getValueSpecification());
    }

    // <set connection statement> ::= SET CONNECTION <connection object>
    private void generate(SetConnectionStatement setConnectionStatement) {
        append(TokenType.SET.getContent());
        append(' ');
        append("CONNECTION");
        append(' ');
        generate(setConnectionStatement.getConnectionObject());
    }

    // <set constraints mode statement>
    // ::=
    // SET CONSTRAINTS <constraint name list> { DEFERRED | IMMEDIATE }
    private void generate(SetConstraintsModeStatement setConstraintsModeStatement) {
        append(TokenType.SET.getContent());
        append(' ');
        append("CONSTRAINTS");
        append(' ');
        generate(setConstraintsModeStatement.getConstraintNameList());
        append(' ');
        if (setConstraintsModeStatement.isDeferred()) {
            append("DEFERRED");
        } else if (setConstraintsModeStatement.isDeferred()) {
            append(TokenType.IMMEDIATE.getContent());
        } else {
            throw new YuliaException(getSql(), getLineNumber(), setConstraintsModeStatement.getBeginIndex(), "This is not supported.");
        }
    }

    // <constraint name list> ::= ALL | <constraint name> [ { <comma> <constraint name> }... ]
    private void generate(ConstraintNameList constraintNameList) {
        if (constraintNameList.isAll()) {
            append(TokenType.ALL.getContent());
            return;
        }
        for (int i = 0; i < constraintNameList.size(); i++) {
            generate(constraintNameList.get(i));
            if (i < constraintNameList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <set descriptor statement>
    // ::=
    // SET [ SQL ] DESCRIPTOR
    // <descriptor name>
    // <set descriptor information>
    private void generate(SetDescriptorStatement setDescriptorStatement) {
        append(TokenType.SET.getContent());
        append(' ');
        if (setDescriptorStatement.isSql()) {
            append(TokenType.SQL.getContent());
            append(' ');
        }
        append("DESCRIPTOR");
        append(' ');
        generate(setDescriptorStatement.getDescriptorName());
        append(' ');
        generate(setDescriptorStatement.getSetDescriptorInformation());
    }

    // <set descriptor information>
    // ::= <set header information> [ { <comma> <set header information> }... ]
    //   | VALUE <item number> <set item information> [ { <comma> <set item information> }... ]
    private void generate(SetDescriptorInformation setDescriptorInformation) {
        SetHeaderInformationList setHeaderInformationList
                = setDescriptorInformation.getSetHeaderInformationList();
        if (setHeaderInformationList != null) {
            generate(setHeaderInformationList);
            return;
        }
        SimpleValueSpecification itemNumber = setDescriptorInformation.getItemNumber();
        if (itemNumber != null) {
            append(TokenType.VALUE.getContent());
            append(' ');
            generate(itemNumber);
            append(' ');
            generate(setDescriptorInformation.getSetItemInformationList());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), setDescriptorInformation.getBeginIndex(), "This is not supported.");
    }

    // <set header information> [ { <comma> <set header information> }... ]
    private void generate(SetHeaderInformationList setHeaderInformationList) {
        for (int i = 0; i < setHeaderInformationList.size(); i++) {
            generate(setHeaderInformationList.get(i));
            if (i < setHeaderInformationList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <set header information>
    // ::=
    // <header item name>
    // <equals operator>
    // <simple value specification 1>
    private void generate(SetHeaderInformation setHeaderInformation) {
        generate(setHeaderInformation.getHeaderItemName());
        append(TokenType.EQUALS_OPERATOR.getContent());
        generate(setHeaderInformation.getSimpleValueSpecification1());
    }

    // <set item information> [ { <comma> <set item information> }... ]
    private void generate(SetItemInformationList setItemInformationList) {
        for (int i = 0; i < setItemInformationList.size(); i++) {
            generate(setItemInformationList.get(i));
            if (i < setItemInformationList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <set item information>
    // ::=
    // <descriptor item name>
    // <equals operator>
    // <simple value specification 2>
    private void generate(SetItemInformation setItemInformation) {
        generate(setItemInformation.getDescriptorItemName());
        append(TokenType.EQUALS_OPERATOR.getContent());
        generate(setItemInformation.getSimpleValueSpecification2());
    }

    // <set local time zone statement> ::= SET TIME ZONE <set time zone value>
    private void generate(SetLocalTimeZoneStatement setLocalTimeZoneStatement) {
        append(TokenType.SET.getContent());
        append(' ');
        append(TokenType.TIME.getContent());
        append(' ');
        append("ZONE");
        append(' ');
        generate(setLocalTimeZoneStatement.getSetTimeZoneValue());
    }

    // <set time zone value> ::= <interval value expression> | LOCAL
    private void generate(SetTimeZoneValue setTimeZoneValue) {
        IntervalValueExpression intervalValueExpression
                = setTimeZoneValue.getIntervalValueExpression();
        if (intervalValueExpression != null) {
            generate(intervalValueExpression);
            return;
        }
        if (setTimeZoneValue.isLocal()) {
            append(TokenType.LOCAL.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), setTimeZoneValue.getBeginIndex(), "This is not supported.");
    }

    // <set names statement> ::= SET NAMES <value specification>
    private void generate(SetNamesStatement setNamesStatement) {
        append(TokenType.SET.getContent());
        append(' ');
        append("NAMES");
        append(' ');
        generate(setNamesStatement.getValueSpecification());
    }

    // <set path statement> ::= SET PATH <value specification>
    private void generate(SetPathStatement setPathStatement) {
        append(TokenType.SET.getContent());
        append(' ');
        append("PATH");
        append(' ');
        generate(setPathStatement.getValueSpecification());
    }

    // <set role statement> ::= SET ROLE <role specification>
    private void generate(SetRoleStatement setRoleStatement) {
        append(TokenType.SET.getContent());
        append(' ');
        append("ROLE");
        append(' ');
        generate(setRoleStatement.getRoleSpecification());
    }

    // <role specification> ::= <value specification> | NONE
    private void generate(RoleSpecification roleSpecification) {
        ValueSpecification valueSpecification = roleSpecification.getValueSpecification();
        if (valueSpecification != null) {
            generate(valueSpecification);
            return;
        }
        append(TokenType.NONE.getContent());
    }

    // <set schema statement> ::= SET SCHEMA <value specification>
    private void generate(SetSchemaStatement setSchemaStatement) {
        append(TokenType.SET.getContent());
        append(' ');
        append("SCHEMA");
        append(' ');
        generate(setSchemaStatement.getValueSpecification());
    }

    // <set session characteristics statement>
    // ::=
    // SET SESSION CHARACTERISTICS AS
    // <session characteristic list>
    private void generate(SetSessionCharacteristicsStatement setSessionCharacteristicsStatement) {
        append(TokenType.SET.getContent());
        append(' ');
        append("SESSION");
        append(' ');
        append("CHARACTERISTICS");
        append(' ');
        append(TokenType.AS.getContent());
        append(' ');
        generate(setSessionCharacteristicsStatement.getSessionCharacteristicList());
    }

    // <session characteristic list> ::= <session characteristic> [ { <comma> <session characteristic> }... ]
    private void generate(SessionCharacteristicList sessionCharacteristicList) {
        for (int i = 0; i < sessionCharacteristicList.size(); i++) {
            generate(sessionCharacteristicList.get(i));
            if (i < sessionCharacteristicList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // SET COLLATION <collation specification> [ FOR <character set specification list> ]
    private void generate(SetSessionCollationStatementSubtype1 setSessionCollationStatementSubtype1) {
        append(TokenType.SET.getContent());
        append(' ');
        append("COLLATION");
        append(' ');
        generate(setSessionCollationStatementSubtype1.getCollationSpecification());
        CharacterSetSpecificationList characterSetSpecificationList
                = setSessionCollationStatementSubtype1.getCharacterSetSpecificationList();
        if (characterSetSpecificationList != null) {
            append(' ');
            append(TokenType.FOR.getContent());
            append(' ');
            generate(characterSetSpecificationList);
        }
    }

    // <character set specification list> ::= <character set specification> [ {<comma> <character set specification> }... ]
    private void generate(CharacterSetSpecificationList characterSetSpecificationList) {
        for (int i = 0; i < characterSetSpecificationList.size(); i++) {
            generate(characterSetSpecificationList.get(i));
            if (i < characterSetSpecificationList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // SET NO COLLATION [ FOR <character set specification list> ]
    private void generate(SetSessionCollationStatementSubtype2 setSessionCollationStatementSubtype2) {
        append(TokenType.SET.getContent());
        append(' ');
        append(TokenType.NO.getContent());
        append(' ');
        append("COLLATION");
        append(' ');
        CharacterSetSpecificationList characterSetSpecificationList
                = setSessionCollationStatementSubtype2.getCharacterSetSpecificationList();
        if (characterSetSpecificationList != null) {
            append(' ');
            append(TokenType.FOR.getContent());
            append(' ');
            generate(characterSetSpecificationList);
        }
    }

    // <set session user identifier statement> ::= SET SESSION AUTHORIZATION <value specification>
    private void generate(SetSessionUserIdentifierStatement setSessionUserIdentifierStatement) {
        append(TokenType.SET.getContent());
        append(' ');
        append("SESSION");
        append(' ');
        append(TokenType.AUTHORIZATION.getContent());
        append(' ');
        generate(setSessionUserIdentifierStatement.getValueSpecification());
    }

    // <set transaction statement> ::= SET [ LOCAL ] <transaction characteristics>
    private void generate(SetTransactionStatement setTransactionStatement) {
        append(TokenType.SET.getContent());
        append(' ');
        if (setTransactionStatement.isLocal()) {
            append(TokenType.LOCAL.getContent());
            append(' ');
        }
        generate(setTransactionStatement.getTransactionCharacteristics());
    }

    // <transaction characteristics>
    // ::=
    // TRANSACTION <transaction mode> [ { <comma> <transaction mode> }... ]
    private void generate(TransactionCharacteristics transactionCharacteristics) {
        append("TRANSACTION");
        append(' ');
        for (int i = 0; i < transactionCharacteristics.size(); i++) {
            generate(transactionCharacteristics.get(i));
            if (i < transactionCharacteristics.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <transaction mode>
    // ::= <isolation level>
    //   | <transaction access mode>
    //   | <diagnostics size>
    private void generate(TransactionMode transactionMode) {
        if (transactionMode instanceof IsolationLevel) {
            generate((IsolationLevel) transactionMode);
            return;
        }
        if (transactionMode instanceof TransactionAccessMode) {
            generate((TransactionAccessMode) transactionMode);
            return;
        }
        if (transactionMode instanceof DiagnosticsSize) {
            generate((DiagnosticsSize) transactionMode);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), transactionMode.getBeginIndex(), "This transaction mode is not supported, " + transactionMode.getClass().getName());
    }

    // <isolation level>
    // ::=
    // ISOLATION
    // LEVEL
    // { READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE }
    private void generate(IsolationLevel isolationLevel) {
        append(TokenType.ISOLATION.getContent());
        append(' ');
        append("LEVEL");
        append(' ');
        if (isolationLevel.isReadUncommitted()) {
            append("READ");
            append(' ');
            append("UNCOMMITTED");
            return;
        }
        if (isolationLevel.isReadCommitted()) {
            append("READ");
            append(' ');
            append("COMMITTED");
            return;
        }
        if (isolationLevel.isRepeatableRead()) {
            append("REPEATABLE");
            append(' ');
            append("READ");
            return;
        }
        if (isolationLevel.isSerializable()) {
            append("SERIALIZABLE");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), isolationLevel.getBeginIndex(), "This isolation level is not supported, " + isolationLevel.getClass().getName());
    }

    // <transaction access mode> ::= READ ONLY | READ WRITE
    private void generate(TransactionAccessMode transactionAccessMode) {
        append("REPEATABLE");
        append(' ');
        if (transactionAccessMode.isReadOnly()) {
            append(TokenType.ONLY.getContent());
            return;
        }
        if (transactionAccessMode.isReadWrite()) {
            append("WRITE");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), transactionAccessMode.getBeginIndex(), "This transaction access mode is not supported, " + transactionAccessMode.getClass().getName());
    }

    // <diagnostics size> ::= DIAGNOSTICS SIZE <number of conditions>
    private void generate(DiagnosticsSize diagnosticsSize) {
        append("DIAGNOSTICS");
        append(' ');
        append("SIZE");
        append(' ');
        generate(diagnosticsSize.getNumberOfConditions());
    }

    // <set transform group statement> ::= SET <transform group characteristic>
    private void generate(SetTransformGroupStatement setTransformGroupStatement) {
        append(TokenType.SET.getContent());
        append(' ');
        generate(setTransformGroupStatement.getTransformGroupCharacteristic());
    }

    // <transform group characteristic>
    // ::= DEFAULT TRANSFORM GROUP <value specification>
    //   | TRANSFORM GROUP FOR TYPE <path-resolved user-defined type name> <value specification>
    private void generate(TransformGroupCharacteristic transformGroupCharacteristic) {
        if (transformGroupCharacteristic instanceof TransformGroupCharacteristicSubtype1) {
            generate((TransformGroupCharacteristicSubtype1) transformGroupCharacteristic);
            return;
        }
        if (transformGroupCharacteristic instanceof TransformGroupCharacteristicSubtype2) {
            generate((TransformGroupCharacteristicSubtype2) transformGroupCharacteristic);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), transformGroupCharacteristic.getBeginIndex(), "This transform group characteristic is not supported, " + transformGroupCharacteristic.getClass().getName());
    }

    // DEFAULT TRANSFORM GROUP <value specification>
    private void generate(TransformGroupCharacteristicSubtype1 transformGroupCharacteristicSubtype1) {
        append(TokenType.DEFAULT.getContent());
        append(' ');
        append("TRANSFORM");
        append(' ');
        append(TokenType.GROUP.getContent());
        append(' ');
        generate(transformGroupCharacteristicSubtype1.getValueSpecification());
    }

    // <value specification> ::= <literal> | <general value specification>
    private void generate(ValueSpecification valueSpecification) {
        if (valueSpecification instanceof Literal) {
            generate((Literal) valueSpecification);
            return;
        }
        if (valueSpecification instanceof GeneralValueSpecification) {
            generate((GeneralValueSpecification) valueSpecification);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), valueSpecification.getBeginIndex(), "This value specification is not supported, " + valueSpecification.getClass().getName());
    }

    // <general value specification>
    // ::= <host parameter specification>
    //   | <SQL parameter reference>
    //   | <dynamic parameter specification>
    //   | <embedded variable specification>
    //   | <current collation specification>
    //   | CURRENT_DEFAULT_TRANSFORM_GROUP
    //   | CURRENT_PATH
    //   | CURRENT_ROLE
    //   | CURRENT_TRANSFORM_GROUP_FOR_TYPE <path-resolved user-defined type name>
    //   | CURRENT_USER
    //   | SESSION_USER
    //   | SYSTEM_USER
    //   | USER
    //   | VALUE
    private void generate(GeneralValueSpecification generalValueSpecification) {
        throw new RuntimeException("TODO");
    }

    // TRANSFORM GROUP FOR TYPE <path-resolved user-defined type name> <value specification>
    private void generate(TransformGroupCharacteristicSubtype2 transformGroupCharacteristicSubtype2) {
        append("TRANSFORM");
        append(' ');
        append(TokenType.GROUP.getContent());
        append(' ');
        append(TokenType.FOR.getContent());
        append(' ');
        append("TYPE");
        append(' ');
        generate(transformGroupCharacteristicSubtype2.getPathResolvedUserDefinedTypeName());
        append(' ');
        generate(transformGroupCharacteristicSubtype2.getValueSpecification());
    }

    // <start transaction statement>
    // ::=
    // START
    // TRANSACTION
    // [ <transaction mode> [ { <comma> <transaction mode> }...] ]
    private void generate(StartTransactionStatement startTransactionStatement) {
        append(TokenType.START.getContent());
        append(' ');
        append("TRANSACTION");
        append(' ');
        for (int i = 0; i < startTransactionStatement.size(); i++) {
            generate(startTransactionStatement.get(i));
            if (i < startTransactionStatement.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <table definition>
    // ::=
    // CREATE
    // [ <table scope> ]
    // TABLE
    // <table name>
    // <table contents source>
    // [ ON COMMIT <table commit action> ROWS ]
    private void generate(TableDefinition tableDefinition) {
        append(TokenType.CREATE.getContent());
        append(' ');
        TableScope tableScope = tableDefinition.getTableScope();
        if (tableScope != null) {
            generate(tableScope);
            append(' ');
        }
        append(TokenType.TABLE.getContent());
        append(' ');
        generate(tableDefinition.getTableName());
        append(' ');
        generate(tableDefinition.getTableContentsSource());
        TableCommitAction tableCommitAction = tableDefinition.getTableCommitAction();
        if (tableCommitAction != null) {
            append(' ');
            append(TokenType.ON.getContent());
            append(' ');
            append(TokenType.COMMIT.getContent());
            append(' ');
            generate(tableCommitAction);
            append(' ');
            append(TokenType.ROWS.getContent());
        }
    }

    // <table contents source>
    // ::= <table element list>
    //   | OF <path-resolved user-defined type name> [ <subtable clause> ] [ <table element list> ]
    //   | <as subquery clause>
    private void generate(TableContentsSource tableContentsSource) {
        if (tableContentsSource instanceof TableElementList) {
            generate((TableElementList) tableContentsSource);
            return;
        }
        if (tableContentsSource instanceof OfPathResolvedUserDefinedTypeName) {
            generate((OfPathResolvedUserDefinedTypeName) tableContentsSource);
            return;
        }
        if (tableContentsSource instanceof AsSubqueryClause) {
            generate((AsSubqueryClause) tableContentsSource);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), tableContentsSource.getBeginIndex(), "This table contents source is not supported, " + tableContentsSource.getClass().getName());
    }

    // <table element list> ::= <left paren> <table element> [ { <comma> <table element> }... ] <right paren>
    private void generate(TableElementList tableElementList) {
        append(TokenType.LEFT_PAREN.getContent());
        for (int i = 0; i < tableElementList.size(); i++) {
            generate(tableElementList.get(i));
            if (i < tableElementList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <table element>
    // ::= <column definition>
    //   | <table constraint definition>
    //   | <like clause>
    //   | <self-referencing column specification>
    //   | <column options>
    private void generate(TableElement tableElement) {
        if (tableElement instanceof ColumnDefinition) {
            generate((ColumnDefinition) tableElement);
            return;
        }
        if (tableElement instanceof TableConstraintDefinition) {
            generate((TableConstraintDefinition) tableElement);
            return;
        }
        if (tableElement instanceof LikeClause) {
            generate((LikeClause) tableElement);
            return;
        }
        if (tableElement instanceof SelfReferencingColumnSpecification) {
            generate((SelfReferencingColumnSpecification) tableElement);
            return;
        }
        if (tableElement instanceof ColumnOptions) {
            generate((ColumnOptions) tableElement);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), tableElement.getBeginIndex(), "This table element is not supported, " + tableElement.getClass().getName());
    }

    // <like clause> ::= LIKE <table name> [ <like options> ]
    private void generate(LikeClause likeClause) {
        append(TokenType.LIKE.getContent());
        append(' ');
        generate(likeClause.getTableName());
        LikeOptions likeOptions = likeClause.getLikeOptions();
        if (likeOptions != null) {
            append(' ');
            generate(likeOptions);
        }
    }

    // <like options> ::= <identity option> | <column default option>
    private void generate(LikeOptions likeOptions) {
        if (likeOptions instanceof IdentityOption) {
            generate((IdentityOption) likeOptions);
            return;
        }
        if (likeOptions instanceof ColumnDefaultOption) {
            generate((ColumnDefaultOption) likeOptions);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), likeOptions.getBeginIndex(), "This like options is not supported, " + likeOptions.getClass().getName());
    }

    // <identity option> ::= INCLUDING IDENTITY | EXCLUDING IDENTITY
    private void generate(IdentityOption identityOption) {
        if (identityOption.isIncludingIdentity()) {
            append("INCLUDING");
            append(' ');
            append(TokenType.IDENTITY.getContent());
            return;
        }
        if (identityOption.isExcludingIdentity()) {
            append("EXCLUDING");
            append(' ');
            append(TokenType.IDENTITY.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), identityOption.getBeginIndex(), "This identity option is not supported.");
    }

    // <column default option> ::= INCLUDING DEFAULTS | EXCLUDING DEFAULTS
    private void generate(ColumnDefaultOption columnDefaultOption) {
        if (columnDefaultOption.isIncludingDefaults()) {
            append("INCLUDING");
            append(' ');
            append("DEFAULTS");
            return;
        }
        if (columnDefaultOption.isExcludingDefaults()) {
            append("EXCLUDING");
            append(' ');
            append("DEFAULTS");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), columnDefaultOption.getBeginIndex(), "This column default option is not supported.");
    }

    // <self-referencing column specification>
    // ::=
    // REF IS
    // <self-referencing column name>
    // <reference generation>
    private void generate(SelfReferencingColumnSpecification selfReferencingColumnSpecification) {
        append(TokenType.REF.getContent());
        append(' ');
        append(TokenType.IS.getContent());
        append(' ');
        generate(selfReferencingColumnSpecification.getSelfReferencingColumnName());
        append(' ');
        generate(selfReferencingColumnSpecification.getReferenceGeneration());
    }

    // <reference generation> ::= SYSTEM GENERATED | USER GENERATED | DERIVED
    private void generate(ReferenceGeneration referenceGeneration) {
        if (referenceGeneration.isSystemGenerated()) {
            append(TokenType.SYSTEM.getContent());
            append(' ');
            append("GENERATED");
            return;
        }
        if (referenceGeneration.isUserGenerated()) {
            append(TokenType.USER.getContent());
            append(' ');
            append("GENERATED");
            return;
        }
        if (referenceGeneration.isDerived()) {
            append("DERIVED");
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), referenceGeneration.getBeginIndex(), "This reference generation is not supported.");
    }

    // <column options> ::= <column name> WITH OPTIONS <column option list>
    private void generate(ColumnOptions columnOptions) {
        generate(columnOptions.getColumnName());
        append(' ');
        append(TokenType.WITH.getContent());
        append(' ');
        append("OPTIONS");
        append(' ');
        generate(columnOptions.getColumnOptionList());
    }

    // <column option list>
    // ::=
    // [ <scope clause> ]
    // [ <default clause> ]
    // [ <column constraint definition> ... ]
    private void generate(ColumnOptionList columnOptionList) {
        ScopeClause scopeClause = columnOptionList.getScopeClause();
        if (scopeClause != null) {
            generate(scopeClause);
        }
        DefaultClause defaultClause = columnOptionList.getDefaultClause();
        if (defaultClause != null) {
            if (scopeClause != null) {
                append(' ');
            }
            generate(defaultClause);
        }
        ColumnConstraintDefinitionList columnConstraintDefinitionList
                = columnOptionList.getColumnConstraintDefinitionList();
        if (columnConstraintDefinitionList != null) {
            if (scopeClause != null || defaultClause != null) {
                append(' ');
            }
            for (int i = 0; i < columnConstraintDefinitionList.size(); i++) {
                generate(columnConstraintDefinitionList.get(i));
                if (i < columnConstraintDefinitionList.size() - 1) {
                    append(' ');
                }
            }
        }
    }

    // OF <path-resolved user-defined type name> [ <subtable clause> ] [ <table element list> ]
    private void generate(OfPathResolvedUserDefinedTypeName ofPathResolvedUserDefinedTypeName) {
        append(TokenType.OF.getContent());
        append(' ');
        generate(ofPathResolvedUserDefinedTypeName.getPathResolvedUserDefinedTypeName());
        SubtableClause subtableClause = ofPathResolvedUserDefinedTypeName.getSubtableClause();
        if (subtableClause != null) {
            append(' ');
            generate(subtableClause);
        }
        TableElementList tableElementList = ofPathResolvedUserDefinedTypeName.getTableElementList();
        if (tableElementList != null) {
            append(' ');
            generate(tableElementList);
        }
    }

    // <subtable clause> ::= UNDER <supertable clause>
    private void generate(SubtableClause subtableClause) {
        append("UNDER");
        append(' ');
        generate(subtableClause.getSupertableClause());
    }

    // <as subquery clause> ::= [ <left paren> <column name list> <right paren> ] AS <subquery> <with or without data>
    private void generate(AsSubqueryClause asSubqueryClause) {
        IdentifierList columnNameList = asSubqueryClause.getColumnNameList();
        if (columnNameList != null) {
            append(TokenType.LEFT_PAREN.getContent());
            generate(columnNameList);
            append(TokenType.RIGHT_PAREN.getContent());
            append(' ');
        }
        append(TokenType.AS.getContent());
        append(' ');
        generate(asSubqueryClause.getSubquery());
        append(' ');
        generate(asSubqueryClause.getWithOrWithoutData());
    }

    // <with or without data> ::= WITH NO DATA | WITH DATA
    private void generate(WithOrWithoutData withOrWithoutData) {
        append(TokenType.WITH.getContent());
        if (withOrWithoutData.isWithNoData()) {
            append(' ');
            append(TokenType.NO.getContent());
        }
        append(' ');
        append("DATA");
    }

    // <table commit action> ::= PRESERVE | DELETE
    private void generate(TableCommitAction tableCommitAction) {
        if (tableCommitAction.isPreserve()) {
            append("PRESERVE");
            return;
        }
        if (tableCommitAction.isDelete()) {
            append(TokenType.DELETE.getContent());
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), tableCommitAction.getBeginIndex(), "This table commit action is not supported.");
    }

    // <table scope> ::= <global or local> TEMPORARY
    // <global or local> ::= GLOBAL | LOCAL
    private void generate(TableScope tableScope) {
        if (tableScope.isGlobal()) {
            append(TokenType.GLOBAL.getContent());
        } else if (tableScope.isLocal()) {
            append(TokenType.LOCAL.getContent());
        } else {
            throw new YuliaException(getSql(), getLineNumber(), tableScope.getBeginIndex(), "This table scope is not supported.");
        }
        append(' ');
        append("TEMPORARY");
    }

    // <transliteration definition>
    // ::=
    // CREATE
    // TRANSLATION
    // <transliteration name>
    // FOR
    // <source character set specification>
    // TO
    // <target character set specification>
    // FROM
    // <transliteration source>
    private void generate(TransliterationDefinition transliterationDefinition) {
        append(TokenType.CREATE.getContent());
        append(' ');
        append(TokenType.TRANSLATION.getContent());
        append(' ');
        generate(transliterationDefinition.getTransliterationName());
        append(' ');
        append(TokenType.FOR.getContent());
        append(' ');
        generate(transliterationDefinition.getSourceCharacterSetSpecification());
        append(' ');
        append(TokenType.TO.getContent());
        append(' ');
        generate(transliterationDefinition.getTargetCharacterSetSpecification());
        append(' ');
        append(TokenType.FROM.getContent());
        append(' ');
        generate(transliterationDefinition.getTransliterationSource());
    }

    // <transliteration source> ::= <existing transliteration name> | <transliteration routine>
    private void generate(TransliterationSource transliterationSource) {
        if (transliterationSource instanceof SchemaQualifiedName) {
            generate((SchemaQualifiedName) transliterationSource);
            return;
        }
        if (transliterationSource instanceof SpecificRoutineDesignator) {
            generate((SpecificRoutineDesignator) transliterationSource);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), transliterationSource.getBeginIndex(), "This transliteration source is not supported, " + transliterationSource.getClass().getName());
    }

    // <trigger definition>
    // ::=
    // CREATE TRIGGER
    // <trigger name>
    // <trigger action time>
    // <trigger event>
    // ON
    // <table name>
    // [ REFERENCING <old or new values alias list> ]
    // <triggered action>
    private void generate(TriggerDefinition triggerDefinition) {
        append(TokenType.CREATE.getContent());
        append(' ');
        append(TokenType.TRIGGER.getContent());
        append(' ');
        generate(triggerDefinition.getTriggerName());
        append(' ');
        generate(triggerDefinition.getTriggerActionTime());
        append(' ');
        generate(triggerDefinition.getTriggerEvent());
        append(' ');
        append(TokenType.ON.getContent());
        append(' ');
        generate(triggerDefinition.getTableName());
        append(' ');
        OldOrNewValuesAliasList oldOrNewValuesAliasList
                = triggerDefinition.getOldOrNewValuesAliasList();
        if (oldOrNewValuesAliasList != null) {
            append(TokenType.REFERENCING.getContent());
            append(' ');
            generate(oldOrNewValuesAliasList);
            append(' ');
        }
        generate(triggerDefinition.getTriggeredAction());
    }

    // <trigger action time> ::= BEFORE | AFTER
    private void generate(TriggerActionTime triggerActionTime) {
        if (triggerActionTime.isBefore()) {
            append("BEFORE");
        } else if (triggerActionTime.isAfter()) {
            append("AFTER");
        } else {
            throw new YuliaException(getSql(), getLineNumber(), triggerActionTime.getBeginIndex(), "This trigger action time is not supported.");
        }
    }

    // <trigger event> ::=  INSERT | DELETE | UPDATE [ OF <trigger column list> ]
    private void generate(TriggerEvent triggerEvent) {
        if (triggerEvent.isInsert()) {
            append(TokenType.INSERT.getContent());
        } else if (triggerEvent.isDelete()) {
            append(TokenType.DELETE.getContent());
        } else if (triggerEvent.isUpdate()) {
            append(TokenType.UPDATE.getContent());
            IdentifierList triggerColumnList = triggerEvent.getTriggerColumnList();
            if (triggerColumnList != null) {
                append(' ');
                append(TokenType.OF.getContent());
                append(' ');
                generate(triggerColumnList);
            }
        } else {
            throw new YuliaException(getSql(), getLineNumber(), triggerEvent.getBeginIndex(), "This trigger event is not supported.");
        }
    }

    // <old or new values alias list> ::= <old or new values alias> ...
    private void generate(OldOrNewValuesAliasList oldOrNewValuesAliasList) {
        for (int i = 0; i < oldOrNewValuesAliasList.size(); i++) {
            generate(oldOrNewValuesAliasList.get(i));
            if (i < oldOrNewValuesAliasList.size() - 1) {
                append(' ');
            }
        }
    }

    // <old or new values alias>
    // ::= OLD [ ROW ] [ AS ] <old values correlation name>
    //   | NEW [ ROW ] [ AS ] <new values correlation name>
    //   | OLD TABLE [ AS ] <old values table alias>
    //   | NEW TABLE [ AS ] <new values table alias>
    private void generate(OldOrNewValuesAlias oldOrNewValuesAlias) {
        if (oldOrNewValuesAlias.isOld()) {
            append(TokenType.OLD.getContent());
        } else if (oldOrNewValuesAlias.isNew()) {
            append(TokenType.NEW.getContent());
        } else {
            throw new YuliaException(getSql(), getLineNumber(), oldOrNewValuesAlias.getBeginIndex(), "This old or new values alias is not supported.");
        }
        append(' ');
        if (oldOrNewValuesAlias.isRow()) {
            append(TokenType.ROW.getContent());
        } else if (oldOrNewValuesAlias.isTable()) {
            append(TokenType.TABLE.getContent());
        } else {
            throw new YuliaException(getSql(), getLineNumber(), oldOrNewValuesAlias.getBeginIndex(), "This old or new values alias is not supported.");
        }
        append(' ');
        append(TokenType.AS.getContent());
        append(' ');
        generate(oldOrNewValuesAlias.getCorrelationNameOrTableAlias());
    }

    // <triggered action>
    // ::=
    // [ FOR EACH { ROW | STATEMENT } ]
    // [ WHEN <left paren> <search condition> <right paren> ]
    // <triggered SQL statement>
    private void generate(TriggeredAction triggeredAction) {
        if (triggeredAction.isForEachRow()) {
            append(TokenType.FOR.getContent());
            append(' ');
            append(TokenType.EACH.getContent());
            append(' ');
            append(TokenType.ROW.getContent());
            append(' ');
        } else if (triggeredAction.isForEachStatement()) {
            append(TokenType.FOR.getContent());
            append(' ');
            append(TokenType.EACH.getContent());
            append(' ');
            append("STATEMENT");
            append(' ');
        }
        BooleanValueExpression searchCondition = triggeredAction.getSearchCondition();
        if (searchCondition != null) {
            append(TokenType.WHEN.getContent());
            append(TokenType.LEFT_PAREN.getContent());
            generate(searchCondition);
            append(TokenType.RIGHT_PAREN.getContent());
            append(' ');
        }
        generate(triggeredAction.getTriggeredSqlStatement());
    }

    // <triggered SQL statement>
    // ::= <SQL procedure statement>
    //   | BEGIN ATOMIC { <SQL procedure statement> <semicolon> }... END
    private void generate(TriggeredSqlStatement triggeredSqlStatement) {
        if (triggeredSqlStatement.isBeginAtomicEnd()) {
            append(TokenType.BEGIN.getContent());
            append(' ');
            append(TokenType.ATOMIC.getContent());
            SqlExecutableStatementList sqlProcedureStatementList
                    = triggeredSqlStatement.getSqlProcedureStatementList();
            for (int i = 0; i < sqlProcedureStatementList.size(); i++) {
                generate(sqlProcedureStatementList.get(i));
                append(TokenType.SEMICOLON.getContent());
            }
            append(TokenType.END.getContent());
            return;
        }
        generate(triggeredSqlStatement.getSqlProcedureStatementList().get(0));
    }

    // UPDATE <target table> SET <set clause list> WHERE CURRENT OF <cursor name>
    // UPDATE <target table> SET <set clause list> [ WHERE <search condition> ]
    // UPDATE <target table> SET <set clause list> WHERE CURRENT OF <dynamic cursor name>
    private void generate(UpdateStatement updateStatement) {
        append(TokenType.UPDATE.getContent());
        append(' ');
        generate(updateStatement.getTargetTable());
        append(' ');
        append(TokenType.SET.getContent());
        append(' ');
        generate(updateStatement.getSetClauseList());
        DynamicCursorName dynamicCursorName = updateStatement.getDynamicCursorName();
        if (dynamicCursorName != null) {
            append(' ');
            append(TokenType.WHERE.getContent());
            append(' ');
            append(TokenType.OF.getContent());
            append(' ');
            generate(updateStatement.getDynamicCursorName());
            return;
        }
        BooleanValueExpression searchCondition = updateStatement.getSearchCondition();
        if (searchCondition != null) {
            append(' ');
            append(TokenType.WHERE.getContent());
            append(' ');
            generate(searchCondition);
        }
    }

    // <set clause list> ::= <set clause> [ { <comma> <set clause> }... ]
    private void generate(SetClauseList setClauseList) {
        for (int i = 0; i < setClauseList.size(); i++) {
            generate(setClauseList.get(i));
            if (i < setClauseList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
    }

    // <set clause>
    // ::= <multiple column assignment>
    //   | <set target> <equals operator> <update source>
    private void generate(SetClause setClause) {
        if (setClause instanceof MultipleColumnAssignment) {
            generate((MultipleColumnAssignment) setClause);
            return;
        }
        if (setClause instanceof SingleColumnAssignment) {
            generate((SingleColumnAssignment) setClause);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), setClause.getBeginIndex(), "This set clause is not supported, " + setClause.getClass().getName());
    }

    // <multiple column assignment> ::= <set target list> <equals operator> <assigned row>
    private void generate(MultipleColumnAssignment multipleColumnAssignment) {
        generate(multipleColumnAssignment.getSetTargetList());
        append(TokenType.EQUALS_OPERATOR.getContent());
        generate(multipleColumnAssignment.getAssignedRow());
    }

    // <contextually typed row value expression>
    // ::= <row value special case>
    //   | <contextually typed row value constructor>
    private void generate(ContextuallyTypedRowValueExpression contextuallyTypedRowValueExpression) {
        if (contextuallyTypedRowValueExpression instanceof NonparenthesizedValueExpressionPrimary) {
            generate((NonparenthesizedValueExpressionPrimary) contextuallyTypedRowValueExpression);
            return;
        }
        if (contextuallyTypedRowValueExpression instanceof ContextuallyTypedRowValueConstructor) {
            generate((ContextuallyTypedRowValueConstructor) contextuallyTypedRowValueExpression);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), contextuallyTypedRowValueExpression.getBeginIndex(), "This contextually typed row value expression is not supported, " + contextuallyTypedRowValueExpression.getClass().getName());
    }

    // <contextually typed row value constructor>
    // ::= <common value expression>
    //   | <boolean value expression>
    //   | <contextually typed value specification>
    //   | <left paren> <contextually typed row value constructor element> <comma> <contextually typed row value constructor element list> <right paren>
    //   | ROW <left paren> <contextually typed row value constructor element list> <right paren>
    private void generate(ContextuallyTypedRowValueConstructor contextuallyTypedRowValueConstructor) {
        if (contextuallyTypedRowValueConstructor instanceof CommonValueExpression) {
            generate((CommonValueExpression) contextuallyTypedRowValueConstructor);
            return;
        }
        if (contextuallyTypedRowValueConstructor instanceof BooleanValueExpression) {
            generate((BooleanValueExpression) contextuallyTypedRowValueConstructor);
            return;
        }
        if (contextuallyTypedRowValueConstructor instanceof ContextuallyTypedValueSpecification) {
            generate((ContextuallyTypedValueSpecification) contextuallyTypedRowValueConstructor);
            return;
        }
        if (contextuallyTypedRowValueConstructor instanceof RowContextuallyTypedRowValueConstructorElementList) {
            generate((RowContextuallyTypedRowValueConstructorElementList) contextuallyTypedRowValueConstructor);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), contextuallyTypedRowValueConstructor.getBeginIndex(), "This contextually typed row value constructor is not supported, " + contextuallyTypedRowValueConstructor.getClass().getName());
    }

    // <left paren> <contextually typed row value constructor element> <comma> <contextually typed row value constructor element list> <right paren>
    // ROW <left paren> <contextually typed row value constructor element list> <right paren>
    private void generate(RowContextuallyTypedRowValueConstructorElementList rowContextuallyTypedRowValueConstructorElementList) {
        if (rowContextuallyTypedRowValueConstructorElementList.isRow()) {
            append(TokenType.ROW.getContent());
        }
        append(TokenType.LEFT_PAREN.getContent());
        for (int i = 0; i < rowContextuallyTypedRowValueConstructorElementList.size(); i++) {
            generate(rowContextuallyTypedRowValueConstructorElementList.get(i));
            if (i < rowContextuallyTypedRowValueConstructorElementList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <contextually typed row value constructor element>
    // ::= <value expression>
    //   | <contextually typed value specification>
    private void generate(ContextuallyTypedRowValueConstructorElement contextuallyTypedRowValueConstructorElement) {
        if (contextuallyTypedRowValueConstructorElement instanceof ValueExpression) {
            generate((ValueExpression) contextuallyTypedRowValueConstructorElement);
            return;
        }
        if (contextuallyTypedRowValueConstructorElement instanceof ContextuallyTypedValueSpecification) {
            generate((ContextuallyTypedValueSpecification) contextuallyTypedRowValueConstructorElement);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), contextuallyTypedRowValueConstructorElement.getBeginIndex(), "This contextually typed row value constructor element is not supported, " + contextuallyTypedRowValueConstructorElement.getClass().getName());
    }

    // <set target list> ::= <left paren> <set target> [ { <comma> <set target> }... ] <right paren>
    private void generate(SetTargetList setTargetList) {
        append(TokenType.LEFT_PAREN.getContent());
        for (int i = 0; i < setTargetList.size(); i++) {
            generate(setTargetList.get(i));
            if (i < setTargetList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <set target> <equals operator> <update source>
    private void generate(SingleColumnAssignment singleColumnAssignment) {
        generate(singleColumnAssignment.getSetTarget());
        append(TokenType.EQUALS_OPERATOR.getContent());
        generate(singleColumnAssignment.getUpdateSource());
    }

    // <set target> ::= <update target> | <mutated set clause>
    private void generate(SetTarget setTarget) {
        if (setTarget instanceof UpdateTarget) {
            generate((UpdateTarget) setTarget);
            return;
        }
        if (setTarget instanceof MutatedSetClause) {
            generate((MutatedSetClause) setTarget);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), setTarget.getBeginIndex(), "This set target is not supported, " + setTarget.getClass().getName());
    }

    // <update target>
    // ::= <object column>
    //   | <object column> <left bracket or trigraph> <simple value specification> <right bracket or trigraph>
    private void generate(UpdateTarget updateTarget) {
        generate(updateTarget.getObjectColumn());
        SimpleValueSpecification simpleValueSpecification = updateTarget.getSimpleValueSpecification();
        if (simpleValueSpecification != null) {
            append(TokenType.LEFT_BRACKET.getContent());
            generate(simpleValueSpecification);
            append(TokenType.RIGHT_BRACKET.getContent());
        }
    }

    // <mutated set clause> ::= <mutated target> <period> <method name>
    private void generate(MutatedSetClause mutatedSetClause) {
        for (int i = 0; i < mutatedSetClause.size(); i++) {
            generate(mutatedSetClause.get(i));
            if (i < mutatedSetClause.size() - 1) {
                append(TokenType.PERIOD.getContent());
                append(' ');
            }
        }
    }

    // <update source> ::= <value expression> | <contextually typed value specification>
    private void generate(UpdateSource updateSource) {
        if (updateSource instanceof ValueExpression) {
            generate((ValueExpression) updateSource);
            return;
        }
        if (updateSource instanceof ContextuallyTypedValueSpecification) {
            generate((ContextuallyTypedValueSpecification) updateSource);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), updateSource.getBeginIndex(), "This update source is not supported, " + updateSource.getClass().getName());
    }

    // <contextually typed value specification>
    // ::= <implicitly typed value specification>
    //   | <default specification>
    private void generate(ContextuallyTypedValueSpecification contextuallyTypedValueSpecification) {
        if (contextuallyTypedValueSpecification instanceof ImplicitlyTypedValueSpecification) {
            generate((ImplicitlyTypedValueSpecification) contextuallyTypedValueSpecification);
            return;
        }
        if (contextuallyTypedValueSpecification instanceof DefaultSpecification) {
            generate((DefaultSpecification) contextuallyTypedValueSpecification);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), contextuallyTypedValueSpecification.getBeginIndex(), "This contextually typed value specification is not supported, " + contextuallyTypedValueSpecification.getClass().getName());
    }

    // <default specification> ::= DEFAULT
    private void generate(DefaultSpecification defaultSpecification) {
        append(TokenType.DEFAULT.getContent());
    }

    // <view definition>
    // ::=
    // CREATE [ RECURSIVE ] VIEW <table name>
    // <view specification>
    // AS <query expression>
    // [ WITH [ <levels clause> ] CHECK OPTION ]
    private void generate(ViewDefinition viewDefinition) {
        append(TokenType.CREATE.getContent());
        append(' ');
        if (viewDefinition.isRecursive()) {
            append(TokenType.RECURSIVE.getContent());
            append(' ');
        }
        append("VIEW");
        append(' ');
        generate(viewDefinition.getTableName());
        append(' ');
        generate(viewDefinition.getViewSpecification());
        append(' ');
        append(TokenType.AS.getContent());
        append(' ');
        generate(viewDefinition.getQueryExpression());
        if (viewDefinition.isWithCascadedCheckOption()) {
            append(' ');
            append(TokenType.WITH.getContent());
            append(' ');
            append(TokenType.CASCADED.getContent());
            append(' ');
            append(TokenType.CHECK.getContent());
            append(' ');
            append("OPTION");
        } else if (viewDefinition.isWithLocalCheckOption()) {
            append(' ');
            append(TokenType.WITH.getContent());
            append(' ');
            append(TokenType.LOCAL.getContent());
            append(' ');
            append(TokenType.CHECK.getContent());
            append(' ');
            append("OPTION");
        } else if (viewDefinition.isWithCheckOption()) {
            append(' ');
            append(TokenType.WITH.getContent());
            append(' ');
            append(TokenType.CHECK.getContent());
            append(' ');
            append("OPTION");
        }
    }

    // <view specification> ::= <regular view specification> | <referenceable view specification>
    private void generate(ViewSpecification viewSpecification) {
        if (viewSpecification instanceof RegularViewSpecification) {
            generate((RegularViewSpecification) viewSpecification);
            return;
        }
        if (viewSpecification instanceof ReferenceableViewSpecification) {
            generate((ReferenceableViewSpecification) viewSpecification);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), viewSpecification.getBeginIndex(), "This view specification is not supported, " + viewSpecification.getClass().getName());
    }

    // <regular view specification> ::= [ <left paren> <view column list> <right paren> ]
    private void generate(RegularViewSpecification regularViewSpecification) {
        append(TokenType.LEFT_PAREN.getContent());
        generate(regularViewSpecification.getViewColumnList());
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <referenceable view specification>
    // ::=
    // OF <path-resolved user-defined type name>
    // [ <subview clause> ]
    // [ <view element list> ]
    private void generate(ReferenceableViewSpecification referenceableViewSpecification) {
        append(TokenType.OF.getContent());
        append(' ');
        generate(referenceableViewSpecification.getPathResolvedUserDefinedTypeName());
        SubviewClause subviewClause = referenceableViewSpecification.getSubviewClause();
        if (subviewClause != null) {
            append(' ');
            generate(subviewClause);
        }
        ViewElementList viewElementList = referenceableViewSpecification.getViewElementList();
        if (viewElementList != null) {
            append(' ');
            generate(viewElementList);
        }
    }

    // <subview clause> ::= UNDER <table name>
    private void generate(SubviewClause subviewClause) {
        append("UNDER");
        append(' ');
        generate(subviewClause.getTableName());
    }

    // <view element list>
    // ::=
    // <left paren>
    // <view element> [ { <comma> <view element> }... ]
    // <right paren>
    private void generate(ViewElementList viewElementList) {
        append(TokenType.LEFT_PAREN.getContent());
        for (int i = 0; i < viewElementList.size(); i++) {
            generate(viewElementList.get(i));
            if (i < viewElementList.size() - 1) {
                append(TokenType.COMMA.getContent());
                append(' ');
            }
        }
        append(TokenType.RIGHT_PAREN.getContent());
    }

    // <view element> ::= <self-referencing column specification> | <view column option>
    private void generate(ViewElement viewElement) {
        if (viewElement instanceof SelfReferencingColumnSpecification) {
            generate((SelfReferencingColumnSpecification) viewElement);
            return;
        }
        if (viewElement instanceof ViewColumnOption) {
            generate((ViewColumnOption) viewElement);
            return;
        }
        throw new YuliaException(getSql(), getLineNumber(), viewElement.getBeginIndex(), "This view element is not supported, " + viewElement.getClass().getName());
    }

    // <view column option> ::= <column name> WITH OPTIONS <scope clause>
    private void generate(ViewColumnOption viewColumnOption) {
        generate(viewColumnOption.getColumnName());
        append(' ');
        append(TokenType.WITH.getContent());
        append(' ');
        append("OPTIONS");
        append(' ');
        generate(viewColumnOption.getScopeClause());
    }

    public String getSql() {
        return PARSER.getSql();
    }

    public int getLineNumber() {
        return PARSER.getLineNumber();
    }

    protected final Generator append(String s) {
        BUFFER.append(s);
        return this;
    }

    protected final Generator append(char c) {
        BUFFER.append(c);
        return this;
    }

}
